ngx-json-ui
Version:
This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 19.2.0.
1 lines • 305 kB
Source Map (JSON)
{"version":3,"file":"ngx-json-ui.mjs","sources":["../../../projects/ngx-json-ui/src/lib/shared/utilities/schema-property.util.ts","../../../projects/ngx-json-ui/src/lib/shared/base/base.component.ts","../../../projects/ngx-json-ui/src/lib/shared/components/type-not-found/type-not-found.component.ts","../../../projects/ngx-json-ui/src/lib/core/services/form-submit-broadcast.service.ts","../../../projects/ngx-json-ui/src/lib/shared/pipes/class-list.pipe.ts","../../../projects/ngx-json-ui/src/lib/shared/pipes/style-map.pipe.ts","../../../projects/ngx-json-ui/src/lib/components/structural/form/form.component.ts","../../../projects/ngx-json-ui/src/lib/components/structural/form/form.component.html","../../../projects/ngx-json-ui/src/lib/features/validator/utilities/joi-validator.util.ts","../../../projects/ngx-json-ui/src/lib/core/models/system/extended-form-control.model.ts","../../../projects/ngx-json-ui/src/lib/features/validator/client/array-validators.ts","../../../projects/ngx-json-ui/src/lib/shared/utilities/form-schema-init.util.ts","../../../projects/ngx-json-ui/src/lib/features/components-mapping/tokens/component-mapping-config.token.ts","../../../projects/ngx-json-ui/src/lib/features/components-mapping/tokens/component-mappings.token.ts","../../../projects/ngx-json-ui/src/lib/components/display/divider/divider.component.ts","../../../projects/ngx-json-ui/src/lib/components/display/divider/divider.component.html","../../../projects/ngx-json-ui/src/lib/shared/pipes/safe-html.pipe.ts","../../../projects/ngx-json-ui/src/lib/components/display/headline/headline.component.ts","../../../projects/ngx-json-ui/src/lib/components/display/headline/headline.component.html","../../../projects/ngx-json-ui/src/lib/components/display/label/label.component.ts","../../../projects/ngx-json-ui/src/lib/components/display/label/label.component.html","../../../projects/ngx-json-ui/src/lib/components/display/paragraph/paragraph.component.ts","../../../projects/ngx-json-ui/src/lib/components/display/paragraph/paragraph.component.html","../../../projects/ngx-json-ui/src/lib/components/display/span/span.component.ts","../../../projects/ngx-json-ui/src/lib/components/display/span/span.component.html","../../../projects/ngx-json-ui/src/lib/components/display/icon/icon.component.ts","../../../projects/ngx-json-ui/src/lib/components/display/icon/icon.component.html","../../../projects/ngx-json-ui/src/lib/components/display/image/image.component.ts","../../../projects/ngx-json-ui/src/lib/components/display/image/image.component.html","../../../projects/ngx-json-ui/src/lib/core/services/region.service.ts","../../../projects/ngx-json-ui/src/lib/components/display/container/container.component.ts","../../../projects/ngx-json-ui/src/lib/shared/base/base-form-array.component.ts","../../../projects/ngx-json-ui/src/lib/shared/utilities/array-operations.util.ts","../../../projects/ngx-json-ui/src/lib/shared/utilities/pagination-helper.ts","../../../projects/ngx-json-ui/src/lib/features/data-population/models/dp-rule.model.ts","../../../projects/ngx-json-ui/src/lib/features/data-population/utilities/dpr-extract-variables.util.ts","../../../projects/ngx-json-ui/src/lib/features/data-population/services/data-population-rule.service.ts","../../../projects/ngx-json-ui/src/lib/components/form-control/arrays/checkbox/checkbox.component.ts","../../../projects/ngx-json-ui/src/lib/components/form-control/arrays/checkbox/checkbox.component.html","../../../projects/ngx-json-ui/src/lib/shared/base/base-form-control.component.ts","../../../projects/ngx-json-ui/src/lib/components/form-control/basic/hidden/hidden.component.ts","../../../projects/ngx-json-ui/src/lib/components/form-control/basic/hidden/hidden.component.html","../../../projects/ngx-json-ui/src/lib/shared/directives/constrained-number.directive.ts","../../../projects/ngx-json-ui/src/lib/components/form-control/basic/number/number.component.ts","../../../projects/ngx-json-ui/src/lib/components/form-control/basic/number/number.component.html","../../../projects/ngx-json-ui/src/lib/components/form-control/basic/radio/radio.component.ts","../../../projects/ngx-json-ui/src/lib/components/form-control/basic/radio/radio.component.html","../../../projects/ngx-json-ui/src/lib/shared/directives/regex-mask.directive.ts","../../../projects/ngx-json-ui/src/lib/shared/directives/input-mask.directive.ts","../../../projects/ngx-json-ui/src/lib/shared/directives/case-insensitive-allowed-values.directive.ts","../../../projects/ngx-json-ui/src/lib/components/form-control/basic/text/text.component.ts","../../../projects/ngx-json-ui/src/lib/components/form-control/basic/text/text.component.html","../../../projects/ngx-json-ui/src/lib/components/form-control/basic/textarea/textarea.component.ts","../../../projects/ngx-json-ui/src/lib/components/form-control/basic/textarea/textarea.component.html","../../../projects/ngx-json-ui/src/lib/features/actions/tokens/action-handler.token.ts","../../../projects/ngx-json-ui/src/lib/features/actions/services/action-factory.service.ts","../../../projects/ngx-json-ui/src/lib/components/actions/button/button.component.ts","../../../projects/ngx-json-ui/src/lib/components/actions/button/button.component.html","../../../projects/ngx-json-ui/src/lib/components/form-control/basic/toggle/toggle.component.ts","../../../projects/ngx-json-ui/src/lib/components/form-control/basic/toggle/toggle.component.html","../../../projects/ngx-json-ui/src/lib/components/form-control/basic/switch/switch.component.ts","../../../projects/ngx-json-ui/src/lib/components/form-control/basic/switch/switch.component.html","../../../projects/ngx-json-ui/src/lib/features/validator/utilities/string-validator.util.ts","../../../projects/ngx-json-ui/src/lib/features/validator/utilities/number-validator.util.ts","../../../projects/ngx-json-ui/src/lib/features/validator/utilities/date-validator.util.ts","../../../projects/ngx-json-ui/src/lib/features/validator/utilities/object-validator.util.ts","../../../projects/ngx-json-ui/src/lib/features/validator/utilities/array-validator.util.ts","../../../projects/ngx-json-ui/src/lib/features/validator/utilities/boolean-validator.util.ts","../../../projects/ngx-json-ui/src/lib/features/validator/utilities/validator-schema-generator.util.ts","../../../projects/ngx-json-ui/src/lib/features/validator/services/joi-validator-factory.service.ts","../../../projects/ngx-json-ui/src/lib/components/form-control/arrays/obj-array/obj-array.component.ts","../../../projects/ngx-json-ui/src/lib/components/form-control/arrays/obj-array/obj-array.component.html","../../../projects/ngx-json-ui/src/lib/components/form-control/arrays/select-array/select-array.component.ts","../../../projects/ngx-json-ui/src/lib/components/form-control/arrays/select-array/select-array.component.html","../../../projects/ngx-json-ui/src/lib/components/form-control/basic/select/select.component.ts","../../../projects/ngx-json-ui/src/lib/components/form-control/basic/select/select.component.html","../../../projects/ngx-json-ui/src/lib/components/overlay/toast/toast.component.ts","../../../projects/ngx-json-ui/src/lib/components/overlay/toast/toast.component.html","../../../projects/ngx-json-ui/src/lib/features/components-mapping/services/component-mapping.service.ts","../../../projects/ngx-json-ui/src/lib/core/services/component-factory.service.ts","../../../projects/ngx-json-ui/src/lib/components/overlay/modal/modal.component.ts","../../../projects/ngx-json-ui/src/lib/components/overlay/modal/modal.component.html","../../../projects/ngx-json-ui/src/lib/core/services/ngx-overlay.service.ts","../../../projects/ngx-json-ui/src/lib/core/services/notification.service.ts","../../../projects/ngx-json-ui/src/lib/interceptors/http-error.interceptor.ts","../../../projects/ngx-json-ui/src/lib/core/core.module.ts","../../../projects/ngx-json-ui/src/lib/core/services/http.service.ts","../../../projects/ngx-json-ui/src/lib/core/services/screen-loader.service.ts","../../../projects/ngx-json-ui/src/lib/features/actions/handlers/api-call.handler.ts","../../../projects/ngx-json-ui/src/lib/features/actions/handlers/load-screen.handler.ts","../../../projects/ngx-json-ui/src/lib/features/actions/handlers/navigation.handler.ts","../../../projects/ngx-json-ui/src/lib/features/actions/handlers/encoded-navigation.handler.ts","../../../projects/ngx-json-ui/src/lib/features/actions/handlers/redirection.handler.ts","../../../projects/ngx-json-ui/src/lib/features/actions/action-feature.module.ts","../../../projects/ngx-json-ui/src/lib/shared/pipes/shared-pipes.module.ts","../../../projects/ngx-json-ui/src/lib/shared/directives/has-tooltip.directive.ts","../../../projects/ngx-json-ui/src/lib/shared/directives/shared-directives.module.ts","../../../projects/ngx-json-ui/src/lib/components/actions/action-components.module.ts","../../../projects/ngx-json-ui/src/lib/components/display/display.module.ts","../../../projects/ngx-json-ui/src/lib/components/structural/structural.module.ts","../../../projects/ngx-json-ui/src/lib/components/form-control/form-control.module.ts","../../../projects/ngx-json-ui/src/lib/components/overlay/overlay.module.ts","../../../projects/ngx-json-ui/src/lib/form-builder.module.ts","../../../projects/ngx-json-ui/src/public-api.ts","../../../projects/ngx-json-ui/src/ngx-json-ui.ts"],"sourcesContent":["//implementing Json classes to overall component\r\nexport function convertStringArrayIntoString(defaultClassName :string, classList: any): string {\r\n // If classList is undefine, null or empty or not type of string array return defaultClassName\r\n if (!classList || classList.length === 0 || !Array.isArray(classList))\r\n return defaultClassName;\r\n \r\n // Join classList string array with help of empty string and return as string\r\n return classList.join(' ');\r\n \r\n}\r\n ","import { Directive, HostBinding, Input } from '@angular/core';\r\nimport { ComponentModel } from '../../core/models/component.model';\r\nimport { convertStringArrayIntoString } from '../utilities/schema-property.util';\r\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\r\n@Directive() // ← tells Angular “process metadata on this class”\r\nexport abstract class BaseComponent<C extends ComponentModel = ComponentModel> {\r\n constructor(protected sanitizer: DomSanitizer) {}\r\n /** \r\n * Importing the ComponentModel interface to define the structure of the component's configuration\r\n * This interface is expected to be defined in the specified path\r\n * The ComponentModel interface is likely to contain properties that define the component's behavior and appearance (Accept this field's as JSON ).\r\n * The @Input decorator allows the component to receive data from its parent component\r\n */\r\n @Input() config!: C; // The component's configuration object\r\n /** Binds to the host element’s `class` attr */\r\n @HostBinding('class') hostClasses = '';\r\n /** Binds to the host element’s `style` attr */\r\n @HostBinding('style') hostStyles = '';\r\n /** Binds to the element’s `class` attr */\r\n classes: string='';\r\n /** Binds to the element’s `style` attr */\r\n styles: { [prop: string]: any } | null = null;\r\n /**\r\n * This method applies host configuration to the component.\r\n * It takes an object with hostClass and hostStyle properties.\r\n * It converts the hostClass to a string\r\n * and assigns it to the hostClasses property.\r\n * It also assigns the hostStyle to the hostStyles property.\r\n * @param {ComponentModel} param0 - The host configuration object.\r\n * @param {string} param0.hostClass - The class to be applied to the host element.\r\n * @param {string} param0.hostStyle - The style to be applied to the host element.\r\n * @returns {void}\r\n * @protected\r\n */\r\n protected applyHostConfig({ hostClass, hostStyle }: C) {\r\n // Convert to string if it's an array or null/undefined\r\n // If it's a string, use it directly. If it's null/undefined, use an empty string.\r\n this.hostClasses = typeof hostClass === 'string'\r\n ? hostClass\r\n : convertStringArrayIntoString('base', hostClass ?? []);\r\n // Convert to string if it's an array or null/undefined\r\n // If it's a string, use it directly. If it's null/undefined, use an empty string.\r\n this.hostStyles = typeof hostStyle === 'string' ? hostStyle : '';\r\n this.hostStyles = this.stringifyStyles(hostStyle) || '';\r\n }\r\n protected applyHostConfigViaClassStyle(config: C) {\r\n // Convert to string if it's an array or null/undefined\r\n // If it's a string, use it directly. If it's null/undefined, use an empty string.\r\n this.hostClasses = typeof config.class === 'string'\r\n ? config.class\r\n : convertStringArrayIntoString('base', config.class ?? []);\r\n // Convert to string if it's an array or null/undefined\r\n // If it's a string, use it directly. If it's null/undefined, use an empty string.\r\n this.hostStyles =this.stringifyStyles(config.style) ?? '';\r\n }\r\n /** \r\n * Converts a style‐object to a CSS string for HostBinding \r\n * This is useful for applying styles dynamically to the host element.\r\n * @param {Record<string,string> | null} [styles] - The styles to be converted to a CSS string.\r\n * @return {string} - The CSS string representation of the styles.\r\n * @private\r\n */\r\n private stringifyStyles(styles?: Record<string,string> | null): string {\r\n if (typeof styles === 'string') return styles;\r\n return styles\r\n ? Object.entries(styles)\r\n .map(([k,v]) => `${k}:${v}`)\r\n .join(';')\r\n : '';\r\n } \r\n}","import { Component, Input } from '@angular/core';\r\n\r\n@Component({\r\n selector: 'nju-type-not-found',\r\n template: `<div class=\"nju-error\">Component type not found.</div>`\r\n})\r\nexport class TypeNotFoundComponent {\r\n@Input() config: any;\r\n}\r\n","import { Injectable } from \"@angular/core\";\r\nimport { BehaviorSubject } from \"rxjs\";\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class FormSubmitBroadcastService {\r\n // BehaviorSubject holds the latest “submitted” flag. \r\n // We start at false (form not yet submitted).\r\n public submitted$ = new BehaviorSubject<boolean>(false);\r\n\r\n // Call this when the user clicks “Submit”\r\n notifySubmitted() {\r\n this.submitted$.next(true);\r\n }\r\n}","import { Pipe, PipeTransform } from '@angular/core';\r\nimport { convertStringArrayIntoString } from '../utilities/schema-property.util';\r\n\r\n@Pipe({\r\n name: 'classList',\r\n pure: true,\r\n standalone: false,\r\n})\r\nexport class ClassListPipe implements PipeTransform {\r\n /**\r\n * Transforms a default class and an optional array of classes into a single string.\r\n * @param classes Array of additional class names (or string if user provided direct class). \r\n * @param defaultCls Base class to apply when array is empty or undefined.\r\n */\r\n transform(\r\n classes: string[] | string | null | undefined,\r\n defaultCls: string): string {\r\n if (typeof classes === 'string') {\r\n return classes;\r\n }\r\n return convertStringArrayIntoString(defaultCls, classes ?? []);\r\n }\r\n}\r\n","import { Pipe, PipeTransform } from '@angular/core';\r\n\r\n@Pipe({\r\n name: 'styleMap',\r\n pure: true,\r\n standalone: false,\r\n})\r\nexport class StyleMapPipe implements PipeTransform {\r\n /**\r\n * Ensures a style binding input is an object for ngStyle.\r\n * Accepts string (CSS text), object, null, or undefined.\r\n * @param styles CSS text or style object.\r\n * @returns Object for ngStyle or leaves string for attr.style.\r\n */\r\n transform(styles?: Record<string,string> | string | null): any {\r\n if (typeof styles === 'string') {\r\n return styles;\r\n }\r\n return styles ?? {};\r\n }\r\n}","// Import core modules\r\nimport { \r\n Component,\r\n ViewContainerRef,\r\n ViewChild,\r\n OnChanges,\r\n ChangeDetectionStrategy,\r\n HostBinding,\r\n SimpleChanges,\r\n Input, \r\n OnDestroy} from '@angular/core';\r\nimport { FormBuilder, FormGroup, FormArray } from '@angular/forms';\r\nimport { DomSanitizer } from '@angular/platform-browser';\r\nimport { Subject } from 'rxjs';\r\nimport { takeUntil } from 'rxjs/operators';\r\nimport { BaseComponent } from '../../../shared/base/base.component';\r\nimport { FormComponentModel } from '../../../core/models/component-models/form-component.model';\r\nimport { JoiValidatorFactoryService } from '../../../features/validator/services/joi-validator-factory.service';\r\nimport { ComponentFactoryService } from '../../../core/services/component-factory.service';\r\n\r\nimport {FormSubmitService} from '../../../core/services/form-submit.service';\r\nimport { initFormControlSchema } from '../../../shared/utilities/form-schema-init.util';\r\nimport { FormSubmitBroadcastService } from '../../../core/services/form-submit-broadcast.service';\r\n\r\n@Component({\r\n selector: 'nju-app-form',\r\n templateUrl: './form.component.html',\r\n standalone: false,\r\n changeDetection: ChangeDetectionStrategy.OnPush\r\n})\r\nexport class FormComponent extends BaseComponent<FormComponentModel> implements OnChanges, OnDestroy {\r\n @HostBinding('id') id = ''; // Binding id to overall component\r\n @HostBinding('attr.data-component-id') cid = ''; // Binding data-component-id to overall component\r\n @Input() form!: FormGroup; // The parent form group, if applicable\r\n // ViewChild decorator is used to get a reference to the dynamic component container in the template\r\n // It allows you to dynamically load components into the view at runtime\r\n // The read property specifies that we want to read the ViewContainerRef from the template reference variable 'formContainer'\r\n @ViewChild('dynamicComponentGroup', { read: ViewContainerRef, static: true }) viewContainerRef!: ViewContainerRef;\r\n\r\n // Subject is used to manage the lifecycle of the component and unsubscribe from observables when the component is destroyed\r\n private destroy$ = new Subject<void>(); // Subject to signal when the component is destroyed\r\n\r\n constructor(protected override sanitizer: DomSanitizer,\r\n private submitBroadcastService: FormSubmitBroadcastService) { \r\n super(sanitizer); \r\n }\r\n\r\n // ngOnChanges is a lifecycle hook that is called when any data-bound input properties change\r\n // This is where you can perform any additional logic when the input properties change\r\n // In this case, it is used to update the host classes and styles based on the component's configuration\r\n ngOnChanges(changes: SimpleChanges): void {\r\n if (changes['config'] && this.config) {\r\n // apply host and component level styling\r\n this.applyHostConfig(this.config);\r\n this.id = this.config['id'] || ''; // Set the id based on the config or default to empty string \r\n this.cid=this.config[\"cid\"] || ''; // Set the cid based on the config or default to empty string\r\n /* Initialize form controls based on the provided validator schema\r\n \r\n initFormControlSchema(\r\n this.config.validatorSchema,\r\n this.form,\r\n this.fb,\r\n this.joiValidatorFactoryService\r\n );\r\n console.log('Form initialized with schema:', this.form?.value);\r\n // Render nested Json UI \r\n if(this.config.components){\r\n this.viewContainerRef.clear();\r\n this.componentFactoryService.loadComponents(\r\n this.config.components ?? [],\r\n this.viewContainerRef,\r\n this.form,\r\n this.config.validatorSchema\r\n );\r\n }\r\n */\r\n \r\n }\r\n }\r\n\r\n // Handler for form submission\r\n onSubmit(): void {\r\n console.log('Form contain invalid value: ', this.form.value);\r\n // 1) Mark the whole form (and all nested arrays/groups) touched first:\r\n this.form.markAllAsTouched();\r\n this.submitBroadcastService.notifySubmitted(); // Notify that the form has been submitted\r\n if (!this.config.onSubmit?.novalidate && this.form.invalid) {\r\n console.log('Form contain invalid value: ', this.form.value);\r\n // Log all validation errors in the form and its nested structures \r\n this.getFormValidationErrors(this.form);\r\n return;\r\n }\r\n /*\r\n this.submitService\r\n .submit(this.config.onSubmit!, this.form.value)\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe({\r\n error: (err) => {\r\n // Global error logging, could delegate to a NotificationService\r\n console.error('Form submission error:', err);\r\n }\r\n });\r\n */\r\n }\r\n /**\r\n * Method to log all validation errors in the form and its nested structures\r\n * Recursively logs all validation errors in a FormGroup/FormArray\r\n */\r\n private getFormValidationErrors(\r\n control: FormGroup | FormArray,\r\n parentKey: string = ''\r\n ): void {\r\n // 1) If this group/array itself has errors, log them\r\n if (control.errors) {\r\n console.error(\r\n `Control: ${parentKey || '(root)'}, Errors:`,\r\n control.errors\r\n );\r\n }\r\n \r\n // 2) Recurse into child controls\r\n Object.keys(control.controls).forEach(name => {\r\n const child = control.get(name)!;\r\n const fullKey = parentKey ? `${parentKey}.${name}` : name;\r\n \r\n if (child instanceof FormGroup || child instanceof FormArray) {\r\n // recurse for nested groups/arrays\r\n this.getFormValidationErrors(child, fullKey);\r\n } else if (child.errors) {\r\n // primitive FormControl errors\r\n Object.entries(child.errors).forEach(([errorKey, errorValue]) => {\r\n console.error(\r\n `Control: ${fullKey}, KeyError: ${errorKey}, ErrorValue:`,\r\n errorValue\r\n );\r\n });\r\n }\r\n });\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this.destroy$.next();\r\n this.destroy$.complete();\r\n }\r\n}\r\n","<form [formGroup]=\"form\"\r\n (ngSubmit)=\"onSubmit()\"\r\n [ngClass]=\"config.class| classList:''\"\r\n [ngStyle]=\"config.style | styleMap\">\r\n <ng-template #dynamicComponentGroup></ng-template>\r\n</form>\r\n","import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';\r\nimport { JoiValidatorFactoryService } from '../services/joi-validator-factory.service';\r\n\r\nexport function joiValidatorUtil(controlName: string, schemaBody: any, validatorFactoryService: JoiValidatorFactoryService): ValidatorFn {\r\n return (control: AbstractControl): ValidationErrors | null => {\r\n const formData = { [controlName]: control.value };\r\n const { error } = validatorFactoryService.validateSchema({ [controlName]: schemaBody }, formData);\r\n if (error) {\r\n const errors: ValidationErrors = {};\r\n error.details.forEach(detail => {\r\n errors[detail.context?.key || 'unknown'] = detail.message;\r\n });\r\n return errors;\r\n }\r\n return null;\r\n };\r\n }","import { FormControl } from '@angular/forms';\r\n\r\nexport class ExtendedFormControl extends FormControl {\r\n metadata?: any;\r\n constructor(formState: any, validatorOrOpts?: any, asyncValidator?: any) {\r\n super(formState, validatorOrOpts, asyncValidator);\r\n }\r\n}","import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';\r\n\r\n/** Ensures the array has at least `min` items */\r\nexport function minItems(min: number): ValidatorFn {\r\n return (control: AbstractControl): ValidationErrors | null =>\r\n Array.isArray(control.value) && control.value.length < min\r\n ? { minItems: { required: min, actual: control.value.length } }\r\n : null;\r\n}\r\n\r\n/** Ensures the array has at most `max` items */\r\nexport function maxItems(max: number): ValidatorFn {\r\n return (control: AbstractControl): ValidationErrors | null =>\r\n Array.isArray(control.value) && control.value.length > max\r\n ? { maxItems: { required: max, actual: control.value.length } }\r\n : null;\r\n}\r\n\r\n/** Ensures all array items are unique */\r\nexport function uniqueItems(): ValidatorFn {\r\n return (control: AbstractControl): ValidationErrors | null => {\r\n const arr = control.value;\r\n if (!Array.isArray(arr)) return null;\r\n const seen = new Set<any>();\r\n for (const v of arr) {\r\n if (seen.has(v)) {\r\n return { uniqueItems: true };\r\n }\r\n seen.add(v);\r\n }\r\n return null;\r\n };\r\n}","import { FormBuilder, FormGroup, FormArray, FormControl, ValidatorFn } from '@angular/forms';\r\nimport { joiValidatorUtil } from '../../features/validator/utilities/joi-validator.util';\r\nimport { JoiValidatorFactoryService } from '../../features/validator/services/joi-validator-factory.service';\r\nimport { ExtendedFormControl } from '../../core/models/system/extended-form-control.model';\r\nimport { maxItems, minItems, uniqueItems } from '../../features/validator/client/array-validators';\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n//////////////////////////////////////////////// Main Function /////////////////////////////////////////////////////////////////\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\nexport function initFormControlSchema(\r\n schema: any, \r\n parent: FormGroup, \r\n fb: FormBuilder, \r\n validatorFactoryService: JoiValidatorFactoryService, \r\n defaultValues: any = {}\r\n) {\r\n for (const key in schema) {\r\n if (schema.hasOwnProperty(key)) {\r\n const fieldSchema = schema[key];\r\n const defaultValue = defaultValues[key] ?? fieldSchema.default ?? null; // Use provided default or schema default\r\n\r\n if (fieldSchema.type === 'object') {\r\n const objectDefaults = defaultValue && typeof defaultValue === 'object' ? defaultValue : {};\r\n parent.addControl(key, createFormGroup(fieldSchema, fb, validatorFactoryService, objectDefaults));\r\n } else if (fieldSchema.type === 'array') {\r\n const arrayDefaults = Array.isArray(defaultValue) ? defaultValue : [];\r\n parent.addControl(key, createFormArray(fieldSchema, fb, validatorFactoryService, arrayDefaults));\r\n } else {\r\n parent.addControl(key, createFormControl(fieldSchema, fb, validatorFactoryService, defaultValue));\r\n }\r\n }\r\n }\r\n}\r\n\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n//////////////////////////////////////////////// Core Functions /////////////////////////////////////////////////////////////////\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\nfunction createFormGroup(\r\n schema: any, \r\n fb: FormBuilder, \r\n validatorFactoryService: JoiValidatorFactoryService, \r\n defaultValues: any = {}\r\n): FormGroup {\r\n const group = fb.group({});\r\n \r\n if (schema.object) {\r\n initFormControlSchema(schema.object, group, fb, validatorFactoryService, defaultValues);\r\n }\r\n\r\n return group;\r\n}\r\nfunction createFormArray(\r\n schema: any,\r\n fb: FormBuilder,\r\n validatorFactoryService: JoiValidatorFactoryService,\r\n defaultValues: any[] = []\r\n ): FormArray {\r\n // 0) Safety: ensure `schema.array` exists\r\n const arrDef = schema?.array;\r\n if (!arrDef) {\r\n console.warn('createFormArray: missing schema.array, returning empty FormArray');\r\n return fb.array([], []);\r\n }\r\n \r\n // 1) Safety: ensure item definition exists\r\n const itemSchema = arrDef.items;\r\n if (!itemSchema) {\r\n console.warn('createFormArray: missing schema.array.items, cannot build children');\r\n const fallbackValidators: ValidatorFn[] = [];\r\n if (arrDef.minItems != null) fallbackValidators.push(minItems(arrDef.minItems));\r\n if (arrDef.maxItems != null) fallbackValidators.push(maxItems(arrDef.maxItems));\r\n if (arrDef.uniqueItems) fallbackValidators.push(uniqueItems());\r\n return fb.array([], fallbackValidators);\r\n }\r\n \r\n // 2) Safety: ensure defaultValues is an array\r\n let defaults: any[];\r\n if (!Array.isArray(defaultValues)) {\r\n console.warn(\r\n `createFormArray: defaultValues for \"${schema?.name}\" is not an array, ignoring it`\r\n );\r\n defaults = [];\r\n } else {\r\n defaults = defaultValues;\r\n }\r\n \r\n // 3) Build child controls\r\n const controls = defaults.map(value =>\r\n createFormItem(itemSchema, fb, validatorFactoryService, value)\r\n );\r\n \r\n // 4) Collect array‐level validators\r\n const arrayValidators: ValidatorFn[] = [];\r\n if (arrDef.minItems != null) arrayValidators.push(minItems(arrDef.minItems));\r\n if (arrDef.maxItems != null) arrayValidators.push(maxItems(arrDef.maxItems));\r\n if (arrDef.uniqueItems) arrayValidators.push(uniqueItems());\r\n \r\n // 5) Return the configured FormArray\r\n return fb.array(controls, arrayValidators);\r\n }\r\nfunction createFormItem(\r\n schema: any, \r\n fb: FormBuilder, \r\n validatorFactoryService: JoiValidatorFactoryService, \r\n defaultValue: any = {}\r\n): FormGroup | FormControl | FormArray {\r\n if (schema.type === 'object') {\r\n return createFormGroup(schema, fb, validatorFactoryService, defaultValue);\r\n } else if (schema.type === 'array') {\r\n const arrayDefaults = Array.isArray(defaultValue) ? defaultValue : schema.default ?? [];\r\n return createFormArray(schema, fb, validatorFactoryService, arrayDefaults);\r\n } else {\r\n return createFormControl(schema, fb, validatorFactoryService, defaultValue);\r\n }\r\n}\r\nfunction createFormControl(\r\n schema: any,\r\n fb: FormBuilder,\r\n validatorFactoryService: JoiValidatorFactoryService,\r\n defaultValue: any = null\r\n): FormControl {\r\n const validators = getValidators(schema, validatorFactoryService);\r\n \r\n // Assign default values properly\r\n const control = new ExtendedFormControl(defaultValue ?? '', validators);\r\n control.metadata = extractConstraints(schema);\r\n\r\n return control;\r\n}\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n///////////////////////////////////////// Supportive Functions //////////////////////////////////////////////////////////////////\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\nfunction getValidators(\r\n schema: any,\r\n validatorFactoryService: JoiValidatorFactoryService) {\r\n const validators = [];\r\n if (schema) {\r\n validators.push(joiValidatorUtil('', schema, validatorFactoryService));\r\n }\r\n return validators;\r\n}\r\nfunction extractConstraints(schema: any) {\r\n const constraints: any = { type: schema.type };\r\n\r\n if (schema.string) {\r\n if (schema.string.pattern) constraints.regexPattern = schema.string.pattern;\r\n if (schema.string.min !== undefined) constraints.min = schema.string.min;\r\n if (schema.string.max !== undefined) constraints.max = schema.string.max;\r\n if (schema.string.length !== undefined) constraints.length = schema.string.length;\r\n if (schema.string.case) constraints.case = schema.string.case;\r\n if (schema.string.creditCard) constraints.maskPattern = \"9999-9999-9999-9999\";\r\n if (schema.string.hostname) constraints.maskPattern = \"*{1,63}.*{1,63}\";\r\n if (schema.string.ip) constraints.maskPattern = schema.string.ip.version.includes('ipv4') ? \"999.999.999.999\" : \"9999:9999:9999:9999:9999:9999:9999:9999\";\r\n if (schema.string.email) constraints.maskPattern = \"*{1,63}@*{1,63}.*{2,6}\";\r\n if (schema.string.alphanum) constraints.maskPattern = \"*{1,}\";\r\n if (schema.string.insensitive) constraints.allowedValues = schema.string.insensitive;\r\n }\r\n\r\n if (schema.number) {\r\n if (schema.number.port) constraints.port = schema.number.port;\r\n if (schema.number.positive) constraints.positive = schema.number.positive;\r\n if (schema.number.multiple !== undefined) constraints.multiple = schema.number.multiple;\r\n if (schema.number.negative) constraints.negative = schema.number.negative;\r\n if (schema.number.precision !== undefined) constraints.precision = schema.number.precision;\r\n if (schema.number.less !== undefined) constraints.less = schema.number.less;\r\n if (schema.number.greater !== undefined) constraints.greater = schema.number.greater;\r\n if (schema.number.min !== undefined) constraints.min = schema.number.min;\r\n if (schema.number.max !== undefined) constraints.max = schema.number.max;\r\n }\r\n if (schema.boolean) {\r\n console.log('boolean:', schema.boolean);\r\n if (schema.boolean.truthy) constraints.truthy = schema.boolean.truthy;\r\n if (schema.boolean.falsy) constraints.falsy = schema.boolean.falsy;\r\n if (schema.boolean.sensitive) constraints.sensitive = true;\r\n }\r\n return constraints;\r\n}","import { InjectionToken } from '@angular/core';\r\nimport { ComponentMappingConfig } from '../models/component-mapping-config';\r\n\r\nexport const COMPONENT_MAPPING_CONFIG = new InjectionToken<ComponentMappingConfig>(\r\n 'COMPONENT_MAPPING_CONFIG',\r\n {\r\n providedIn: 'root',\r\n factory: () => ({ useDefaultMappings: true }) // Defaults to using the built-in mappings.\r\n }\r\n);","import { InjectionToken } from '@angular/core';\r\nimport { ComponentMappingModel } from '../models/component-mapping.model';\r\n\r\nexport const COMPONENT_MAPPINGS = new InjectionToken<ComponentMappingModel[]>(\r\n 'COMPONENT_MAPPINGS'\r\n);","import { ChangeDetectionStrategy, Component, OnChanges, SimpleChanges } from '@angular/core';\r\nimport { BaseComponent } from '../../../shared/base/base.component';\r\n\r\n@Component({\r\n selector: 'nju-divider',\r\n standalone: false,\r\n templateUrl: './divider.component.html',\r\n changeDetection: ChangeDetectionStrategy.OnPush\r\n})\r\nexport class DividerComponent extends BaseComponent implements OnChanges { \r\n // ngOnChanges is a lifecycle hook that is called when any data-bound input properties change\r\n // This is where you can perform any additional logic when the input properties change\r\n // In this case, it is used to update the host classes and styles based on the component's configuration\r\n ngOnChanges(changes: SimpleChanges): void {\r\n if (changes['config'] && this.config) {\r\n // apply host and component level styling\r\n this.applyHostConfig(this.config); \r\n }\r\n }\r\n}\r\n","<hr \r\n [ngClass]=\"config.class | classList:'border-medium'\" \r\n [ngStyle]=\"config.style | styleMap\"/>","import { Pipe, PipeTransform } from '@angular/core';\r\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\r\n\r\n@Pipe({\r\n name: 'safeHtml',\r\n pure: true,\r\n standalone: false,\r\n})\r\nexport class SafeHtmlPipe implements PipeTransform {\r\n constructor(private sanitizer: DomSanitizer) {}\r\n\r\n transform(html: string | null | undefined): SafeHtml {\r\n // default to empty string if null/undefined\r\n return this.sanitizer.bypassSecurityTrustHtml(html ?? '');\r\n }\r\n}","import { ChangeDetectionStrategy, Component, OnChanges, SimpleChanges } from '@angular/core';\r\nimport { BaseComponent } from '../../../shared/base/base.component';\r\n@Component({\r\n selector: 'nju-headline',\r\n standalone: false,\r\n templateUrl: './headline.component.html',\r\n changeDetection: ChangeDetectionStrategy.OnPush\r\n})\r\nexport class HeadlineComponent extends BaseComponent implements OnChanges {\r\n // ngOnChanges is a lifecycle hook that is called when any data-bound input properties change\r\n // This is where you can perform any additional logic when the input properties change\r\n // In this case, it is used to update the host classes and styles based on the component's configuration\r\n ngOnChanges(changes: SimpleChanges): void {\r\n // Check if the 'config' input property has changed\r\n // If it has, and the config is defined, apply the host and component configuration\r\n if (changes['config'] && this.config) {\r\n // Set css styling variable from json schema\r\n // apply host and component level styling\r\n this.applyHostConfig(this.config); \r\n }\r\n }\r\n}","<ng-container [ngSwitch]=\"config['tag']\">\r\n <h1 [ngClass]=\"config.class | classList:''\" [ngStyle]=\"config.style | styleMap\" *ngSwitchCase=\"'h1'\" [innerHTML]=\"config['text'] | safeHtml\" [attr.data-component-id]=\"config['cid']\"></h1>\r\n <h2 [ngClass]=\"config.class | classList:''\" [ngStyle]=\"config.style | styleMap\" *ngSwitchCase=\"'h2'\" [innerHTML]=\"config['text'] | safeHtml\" [attr.data-component-id]=\"config['cid']\"></h2>\r\n <h3 [ngClass]=\"config.class | classList:''\" [ngStyle]=\"config.style | styleMap\" *ngSwitchCase=\"'h3'\" [innerHTML]=\"config['text'] | safeHtml\" [attr.data-component-id]=\"config['cid']\"></h3>\r\n <h4 [ngClass]=\"config.class | classList:''\" [ngStyle]=\"config.style | styleMap\" *ngSwitchCase=\"'h4'\" [innerHTML]=\"config['text'] | safeHtml\" [attr.data-component-id]=\"config['cid']\"></h4>\r\n <h5 [ngClass]=\"config.class | classList:''\" [ngStyle]=\"config.style | styleMap\" *ngSwitchCase=\"'h5'\" [innerHTML]=\"config['text'] | safeHtml\" [attr.data-component-id]=\"config['cid']\"></h5>\r\n <h6 [ngClass]=\"config.class | classList:''\" [ngStyle]=\"config.style | styleMap\" *ngSwitchCase=\"'h6'\" [innerHTML]=\"config['text'] | safeHtml\" [attr.data-component-id]=\"config['cid']\"></h6>\r\n <div [ngClass]=\"config.class | classList:''\" [ngStyle]=\"config.style | styleMap\" *ngSwitchDefault [innerHTML]=\"config['text'] | safeHtml\" [attr.data-component-id]=\"config['cid']\"></div>\r\n</ng-container>","import { ChangeDetectionStrategy, Component, OnChanges, SimpleChanges } from '@angular/core';\r\nimport { BaseComponent } from '../../../shared/base/base.component';\r\n\r\n@Component({\r\n selector: 'nju-label',\r\n standalone: false,\r\n templateUrl: './label.component.html',\r\n changeDetection: ChangeDetectionStrategy.OnPush\r\n})\r\nexport class LabelComponent extends BaseComponent implements OnChanges {\r\n // ngOnChanges is a lifecycle hook that is called when any data-bound input properties change\r\n // This is where you can perform any additional logic when the input properties change\r\n // In this case, it is used to update the host classes and styles based on the component's configuration\r\n ngOnChanges(changes: SimpleChanges): void {\r\n // Check if the 'config' input property has changed\r\n // If it has, and the config is defined, apply the host and component configuration\r\n if (changes['config'] && this.config) {\r\n // Set css styling variable from json schema\r\n // apply host and component level styling\r\n this.applyHostConfig(this.config);\r\n }\r\n }\r\n}","<label \r\n [ngClass]=\"config.class | classList:'form-label'\"\r\n [ngStyle]=\"config.style | styleMap\" \r\n [attr.for]=\"config['controlId'] ?? null\"\r\n [innerHTML]=\"config['text'] | safeHtml\"\r\n [attr.data-component-id]=\"config['cid']\">\r\n</label>","import { ChangeDetectionStrategy, Component, OnChanges, SimpleChanges } from '@angular/core';\r\nimport { BaseComponent } from '../../../shared/base/base.component';\r\n@Component({\r\n selector: 'nju-paragraph',\r\n standalone: false,\r\n templateUrl: './paragraph.component.html',\r\n changeDetection: ChangeDetectionStrategy.OnPush\r\n})\r\nexport class ParagraphComponent extends BaseComponent implements OnChanges {\r\n // ngOnChanges is a lifecycle hook that is called when any data-bound input properties change\r\n // This is where you can perform any additional logic when the input properties change\r\n // In this case, it is used to update the host classes and styles based on the component's configuration\r\n ngOnChanges(changes: SimpleChanges): void {\r\n // Check if the 'config' input property has changed\r\n // If it has, and the config is defined, apply the host and component configuration\r\n if (changes['config'] && this.config) {\r\n // Set css styling variable from json schema\r\n // apply host and component level styling\r\n this.applyHostConfig(this.config);\r\n }\r\n }\r\n}\r\n","<p \r\n [ngClass]=\"config.class | classList:'body-lg'\"\r\n [ngStyle]=\"config.style | styleMap\"\r\n [innerHTML]=\"config['text'] | safeHtml\"\r\n [attr.data-component-id]=\"config['cid']\"></p>","import { ChangeDetectionStrategy, Component, OnChanges, SimpleChanges } from '@angular/core';\r\nimport { BaseComponent } from '../../../shared/base/base.component';\r\n\r\n@Component({\r\n selector: 'nju-span',\r\n templateUrl: './span.component.html',\r\n standalone: false,\r\n changeDetection: ChangeDetectionStrategy.OnPush\r\n})\r\nexport class SpanComponent extends BaseComponent implements OnChanges {\r\n // ngOnChanges is a lifecycle hook that is called when any data-bound input properties change\r\n // This is where you can perform any additional logic when the input properties change\r\n // In this case, it is used to update the host classes and styles based on the component's configuration\r\n ngOnChanges(changes: SimpleChanges): void {\r\n // Check if the 'config' input property has changed\r\n // If it has, and the config is defined, apply the host and component configuration\r\n if (changes['config'] && this.config) {\r\n // Set css styling variable from json schema\r\n // apply host and component level styling\r\n this.applyHostConfig(this.config);\r\n }\r\n }\r\n}\r\n","<span \r\n [ngClass]=\"config.class | classList:''\"\r\n [ngStyle]=\"config.style | styleMap\" \r\n [innerHTML]=\"config['text'] | safeHtml\"\r\n [attr.data-component-id]=\"config['cid']\">\r\n</span>","import { ChangeDetectionStrategy, Component, HostBinding, Input, OnChanges, SimpleChanges } from '@angular/core';\r\nimport { BaseComponent } from '../../../shared/base/base.component';\r\n@Component({\r\n selector: 'nju-icon',\r\n templateUrl: './icon.component.html',\r\n standalone: false,\r\n changeDetection: ChangeDetectionStrategy.OnPush\r\n})\r\nexport class IconComponent extends BaseComponent implements OnChanges {\r\n // ngOnChanges is a lifecycle hook that is called when any data-bound input properties change\r\n // This is where you can perform any additional logic when the input properties change\r\n // In this case, it is used to update the host classes and styles based on the component's configuration\r\n ngOnChanges(changes: SimpleChanges): void {\r\n // Check if the 'config' input property has changed\r\n // If it has, and the config is defined, apply the host and component configuration\r\n if (changes['config'] && this.config) {\r\n // Set css styling variable from json schema\r\n // apply host and component level styling\r\n this.applyHostConfig(this.config);\r\n }\r\n }\r\n}","<i [ngClass]=\"config.class| classList:''\" [ngStyle]=\"config.style | styleMap\"></i>","import { ChangeDetectionStrategy, Component, HostBinding, Input, OnChanges, SimpleChanges } from '@angular/core';\r\nimport { BaseComponent } from '../../../shared/base/base.component';\r\n\r\n@Component({\r\n selector: 'nju-image',\r\n templateUrl: './image.component.html',\r\n standalone: false,\r\n changeDetection: ChangeDetectionStrategy.OnPush\r\n})\r\nexport class ImageComponent extends BaseComponent implements OnChanges {\r\n // ngOnChanges is a lifecycle hook that is called when any data-bound input properties change\r\n // This is where you can perform any additional logic when the input properties change\r\n // In this case, it is used to update the host classes and styles based on the component's configuration\r\n ngOnChanges(changes: SimpleChanges): void {\r\n // Check if the 'config' input property has changed\r\n // If it has, and the config is defined, apply the host and component configuration\r\n if (changes['config'] && this.config) {\r\n // Set css styling variable from json schema\r\n // apply host and component level styling\r\n this.applyHostConfig(this.config); \r\n }\r\n }\r\n}\r\n","<img\r\n [ngClass]=\"config.class | classList:''\" \r\n [ngStyle]=\"config.style | styleMap\"\r\n [attr.data-bs-custom-class]=\"config['tooltipCustomClass']\" \r\n [attr.data-bs-toggle]=\"'tooltip'\"\r\n [attr.data-bs-placement]=\"config['tooltipPlacement']\" \r\n [attr.title]=\"config['tooltip']\" \r\n [src]=\"config['src']\" />","import { Injectable, ViewContainerRef } from \"@angular/core\";\r\n\r\n// src/lib/services/region.service.ts\r\n@Injectable({providedIn:'root'})\r\nexport class RegionService {\r\n private regions = new Map<string, ViewContainerRef>();\r\n register(cid: string, vcr: ViewContainerRef) {\r\n this.regions.set(cid, vcr);\r\n }\r\n unregister(cid: string) {\r\n this.regions.delete(cid);\r\n }\r\n get(cid: string): ViewContainerRef | undefined {\r\n return this.regions.get(cid);\r\n }\r\n}","import { ChangeDetectionStrategy, Component, HostBinding, OnChanges, OnDestroy, SimpleChanges, ViewChild, ViewContainerRef } from '@angular/core';\r\nimport { BaseComponent } from '../../../shared/base/base.component';\r\nimport { RegionService } from '../../../core/services/region.service';\r\nimport { DomSanitizer } from '@angular/platform-browser';\r\n@Component({\r\n selector: 'nju-container',\r\n template: `<ng-template #dynamicComponentGroup></ng-template>`,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n standalone:false,\r\n})\r\nexport class ContainerComponent extends BaseComponent implements OnChanges, OnDestroy { \r\n // HostBinding decorator is used to bind properties to the host element of the component\r\n // It allows you to bind properties to the host element of the component\r\n constructor(\r\n private regions: RegionService,\r\n protected override sanitizer: DomSanitizer\r\n ) {\r\n super(sanitizer); \r\n }\r\n // HostBinding decorator is used to bind properties to the host element of the component\r\n @HostBinding('id') id = ''; // Binding id to overall component\r\n @HostBinding('attr.data-component-id') cid = ''; // Binding data-component-id to overall component\r\n // ViewChild decorator is used to get a reference to the dynamic component container in the template\r\n // It allows you to dynamically load components into the view at runtime\r\n // The read property specifies that we want to read the ViewContainerRef from the template reference variable 'dynamicComponentGroup'\r\n @ViewChild('dynamicComponentGroup', { read: ViewContainerRef, static: true }) viewContainerRef!: ViewContainerRef;\r\n // ngOnChanges is a lifecycle hook that is called when any data-bound input properties change\r\n // This is where you can perform any additional logic when the input properties change\r\n // In this case, it is used to update the host classes and styles based on the component's configuration\r\n ngOnChanges(changes: SimpleChanges): void {\r\n if (changes['config'] && this.config) {\r\n // apply host and component level styling\r\n this.applyHostConfigViaClassStyle(this.config); \r\n this.id = this.config['id'] || ''; // Set the id based on the config or default to empty string \r\n this.cid=this.config[\"cid\"] || ''; // Set the cid based on the config or default to empty string\r\n\r\n const cid = this.config.cid || '';\r\n this.regions.register(cid, this.viewContainerRef);\r\n }\r\n }\r\n \r\n ngOnDestroy() {\r\n this.regions.unregister(this.config.cid || '');\r\n }\r\n}","import {\r\n Directive,\r\n HostBinding,\r\n Input,\r\n OnChanges,\r\n SimpleChanges,\r\n OnDestroy,\r\n ChangeDetectorRef\r\n} from '@angular/core';\r\nimport { FormGroup, FormArray, FormBuilder, ValidationErrors } from '@angular/forms';\r\nimport { Subject } from 'rxjs';\r\nimport { takeUntil } from 'rxjs/operators';\r\nimport { BaseComponent } from './base.component';\r\nimport { DomSanitizer } from '@angular/platform-browser';\r\nimport { FormSubmitBroadcastService } from '../../core/services/form-submit-broadcast.service';\r\nimport { FormControlComponentModel } from '../../core/models/component-models/form-control-component.model';\r\n\r\n@Directive()\r\nexport abstract class BaseFormArrayComponent<\r\n M extends FormControlComponentModel = FormControlComponentModel\r\n> extends BaseComponent<M> implements OnChanges, OnDestroy {\r\n /** Emits on destroy to clean up subscriptions */\r\n private destroy$ = new Subject<void>();\r\n\r\n /** Underlying FormArray */\r\n protected formArray!: FormArray;\r\n\r\