mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[AAE-3587] Use grid to allow using rowspan (#6151)
* AAE-3587 Use material grid to allow using rowspan * AAE-3587 Fix column field rowspan * AAE-3587 Add enableFixedSpace default value * AAE-3587 Change material grid to CSS grid area * AAE-3587 Review comments * AAE-3587 Refactor for clarification of the complex method * AAE-3587 Add types to method signatures
This commit is contained in:
committed by
GitHub
parent
04f5e35e05
commit
b3e8ff27af
@@ -329,15 +329,15 @@ describe('Form Renderer Component', () => {
|
|||||||
formRendererComponent.formDefinition = formService.parseForm(colspanForm.formRepresentation.formDefinition, null , false, false);
|
formRendererComponent.formDefinition = formService.parseForm(colspanForm.formRepresentation.formDefinition, null , false, false);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
await fixture.whenStable();
|
await fixture.whenStable();
|
||||||
const formSizedElement = fixture.nativeElement.querySelector('#field-2bc275fb-e113-4d7d-885f-6e74a7332d40-container section.adf-grid-list-column-view');
|
const formSizedElement = fixture.nativeElement.querySelector('#field-2bc275fb-e113-4d7d-885f-6e74a7332d40-container div.adf-grid-list');
|
||||||
expectElementToBeVisible(formSizedElement);
|
expectElementToBeVisible(formSizedElement);
|
||||||
const sectionGridElement: HTMLElement[] = fixture.nativeElement.querySelectorAll('#field-2bc275fb-e113-4d7d-885f-6e74a7332d40-container section .adf-grid-list-single-column');
|
const sectionGridElement: HTMLElement[] = fixture.nativeElement.querySelectorAll('#field-2bc275fb-e113-4d7d-885f-6e74a7332d40-container div .adf-grid-list-item');
|
||||||
sectionGridElement.forEach((element) => {
|
sectionGridElement.forEach((element) => {
|
||||||
expect(element.style['width']).toBe('50%', 'Elemens is wrong sized for this section');
|
expect(element.style['grid-area']).toBe('auto / auto / span 1 / span 1', 'Elemens is wrong sized for this section');
|
||||||
});
|
});
|
||||||
|
|
||||||
const fullWidthElement = fixture.nativeElement.querySelector('#field-d52ada4e-cbdc-4f0c-a480-5b85fa00e4f8-container section.adf-grid-list-column-view .adf-grid-list-single-column');
|
const fullWidthElement = fixture.nativeElement.querySelector('#field-d52ada4e-cbdc-4f0c-a480-5b85fa00e4f8-container div.adf-grid-list .adf-grid-list-item');
|
||||||
expect(fullWidthElement.style['width']).toBe('100%');
|
expect(fullWidthElement.style['grid-area']).toBe('auto / auto / span 1 / span 2');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('[C309655] - Should display validation error message when Number widget has invalid value', async () => {
|
it('[C309655] - Should display validation error message when Number widget has invalid value', async () => {
|
||||||
|
@@ -12,11 +12,13 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="field?.form?.enableFixedSpace else fixingTemplate">
|
<div *ngIf="field?.form?.enableFixedSpace else fixingTemplate">
|
||||||
<section class="adf-grid-list" *ngIf="content?.isExpanded">
|
<div class="adf-grid-list" [ngStyle]="{ 'grid-template-columns': 'repeat('+numberOfColumns+', 1fr)'}"
|
||||||
<div class="adf-grid-list-item" *ngFor="let field of fields" [style.width.%]="getColumnWith(field)">
|
*ngIf="content?.isExpanded">
|
||||||
|
<div class="adf-grid-list-item" *ngFor="let field of fields"
|
||||||
|
[ngStyle]="{'grid-area': 'auto / auto / span '+(field?.rowspan || 1)+' / span '+(field?.colspan || 1)}">
|
||||||
<adf-form-field *ngIf="field" [field]="field"></adf-form-field>
|
<adf-form-field *ngIf="field" [field]="field"></adf-form-field>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ng-template #fixingTemplate>
|
<ng-template #fixingTemplate>
|
||||||
@@ -28,5 +30,3 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
|
|
||||||
|
@@ -57,14 +57,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.adf-grid-list {
|
.adf-grid-list {
|
||||||
display: flex;
|
display: grid;
|
||||||
flex-wrap: wrap;
|
|
||||||
margin-left: -1%;
|
|
||||||
margin-right: -1%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.adf-grid-list-item {
|
.adf-grid-list-item {
|
||||||
flex-grow: 1;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding-left: 1%;
|
padding-left: 1%;
|
||||||
padding-right: 1%;
|
padding-right: 1%;
|
||||||
@@ -119,5 +115,9 @@
|
|||||||
width: 80%;
|
width: 80%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
adf-form-field {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,7 +17,6 @@
|
|||||||
|
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { ContainerColumnModel } from './../core/container-column.model';
|
|
||||||
import { FormFieldTypes } from './../core/form-field-types';
|
import { FormFieldTypes } from './../core/form-field-types';
|
||||||
import { FormFieldModel } from './../core/form-field.model';
|
import { FormFieldModel } from './../core/form-field.model';
|
||||||
import { FormModel } from './../core/form.model';
|
import { FormModel } from './../core/form.model';
|
||||||
@@ -103,7 +102,7 @@ describe('ContainerWidgetComponent', () => {
|
|||||||
|
|
||||||
it('should send an event when a value is changed in the form', (done) => {
|
it('should send an event when a value is changed in the form', (done) => {
|
||||||
const fakeForm = new FormModel();
|
const fakeForm = new FormModel();
|
||||||
const fakeField = new FormFieldModel(fakeForm, {id: 'fakeField', value: 'fakeValue'});
|
const fakeField = new FormFieldModel(fakeForm, { id: 'fakeField', value: 'fakeValue' });
|
||||||
widget.fieldChanged.subscribe((field) => {
|
widget.fieldChanged.subscribe((field) => {
|
||||||
expect(field).not.toBe(null);
|
expect(field).not.toBe(null);
|
||||||
expect(field.id).toBe('fakeField');
|
expect(field.id).toBe('fakeField');
|
||||||
@@ -117,30 +116,22 @@ describe('ContainerWidgetComponent', () => {
|
|||||||
describe('fields', () => {
|
describe('fields', () => {
|
||||||
|
|
||||||
it('should serializes the content fields', () => {
|
it('should serializes the content fields', () => {
|
||||||
const field1 = <FormFieldModel> {id: '1'},
|
const form = new FormModel();
|
||||||
field2 = <FormFieldModel> {id: '2'},
|
const json = {
|
||||||
field3 = <FormFieldModel> {id: '3'},
|
id: 'test',
|
||||||
field4 = <FormFieldModel> {id: '4'},
|
name: 'test',
|
||||||
field5 = <FormFieldModel> {id: '5'},
|
type: 'container',
|
||||||
field6 = <FormFieldModel> {id: '6'};
|
tab: null,
|
||||||
|
fields: {
|
||||||
|
'1' : [{ id: '1' }, { id: '2' }, { id: '3' }],
|
||||||
|
'2' : [{ id: '4' }, { id: '5' }],
|
||||||
|
'3' : [{ id: '6' }]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const container = new ContainerWidgetComponentModel(new FormFieldModel(new FormModel()));
|
const field = new FormFieldModel(form, json);
|
||||||
container.columns = [
|
widget.field = field;
|
||||||
<ContainerColumnModel> { fields: [
|
widget.ngOnInit();
|
||||||
field1,
|
|
||||||
field2,
|
|
||||||
field3
|
|
||||||
] },
|
|
||||||
<ContainerColumnModel> { fields: [
|
|
||||||
field4,
|
|
||||||
field5
|
|
||||||
] },
|
|
||||||
<ContainerColumnModel> { fields: [
|
|
||||||
field6
|
|
||||||
] }
|
|
||||||
];
|
|
||||||
|
|
||||||
widget.content = container;
|
|
||||||
|
|
||||||
expect(widget.fields[0].id).toEqual('1');
|
expect(widget.fields[0].id).toEqual('1');
|
||||||
expect(widget.fields[1].id).toEqual('4');
|
expect(widget.fields[1].id).toEqual('4');
|
||||||
@@ -152,6 +143,99 @@ describe('ContainerWidgetComponent', () => {
|
|||||||
expect(widget.fields[7]).toEqual(undefined);
|
expect(widget.fields[7]).toEqual(undefined);
|
||||||
expect(widget.fields[8]).toEqual(undefined);
|
expect(widget.fields[8]).toEqual(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should serializes the content fields with rowspan', () => {
|
||||||
|
const form = new FormModel();
|
||||||
|
const json = {
|
||||||
|
id: 'test',
|
||||||
|
name: 'test',
|
||||||
|
type: 'container',
|
||||||
|
tab: null,
|
||||||
|
fields: {
|
||||||
|
'1': [
|
||||||
|
{
|
||||||
|
id: 'a',
|
||||||
|
colspan: 2,
|
||||||
|
rowspan: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'b'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'c'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'd'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'e',
|
||||||
|
colspan: 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'f'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'g'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'h',
|
||||||
|
colspan: 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'2': [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
rowspan: 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
rowspan: 2,
|
||||||
|
colspan: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'3': [
|
||||||
|
{
|
||||||
|
id: 'white'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'black'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'green',
|
||||||
|
rowspan: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'yellow'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const field = new FormFieldModel(form, json);
|
||||||
|
widget.field = field;
|
||||||
|
widget.ngOnInit();
|
||||||
|
|
||||||
|
expect(widget.fields.length).toEqual(17);
|
||||||
|
expect(widget.fields[0].id).toEqual('a');
|
||||||
|
expect(widget.fields[1].id).toEqual('white');
|
||||||
|
expect(widget.fields[2].id).toEqual('b');
|
||||||
|
expect(widget.fields[3].id).toEqual('1');
|
||||||
|
expect(widget.fields[4].id).toEqual('black');
|
||||||
|
expect(widget.fields[5].id).toEqual('c');
|
||||||
|
expect(widget.fields[6].id).toEqual('green');
|
||||||
|
expect(widget.fields[7].id).toEqual('d');
|
||||||
|
expect(widget.fields[8].id).toEqual('e');
|
||||||
|
expect(widget.fields[9].id).toEqual('f');
|
||||||
|
expect(widget.fields[10].id).toEqual('2');
|
||||||
|
expect(widget.fields[11].id).toEqual('g');
|
||||||
|
expect(widget.fields[12].id).toEqual('h');
|
||||||
|
expect(widget.fields[13].id).toEqual('yellow');
|
||||||
|
expect(widget.fields[14]).toEqual(undefined);
|
||||||
|
expect(widget.fields[15].id).toEqual('3');
|
||||||
|
expect(widget.fields[16]).toEqual(undefined);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getColumnWith', () => {
|
describe('getColumnWith', () => {
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* tslint:disable:component-selector */
|
/* tslint:disable:component-selector */
|
||||||
|
|
||||||
import { AfterViewInit, Component, OnInit, ViewEncapsulation } from '@angular/core';
|
import { AfterViewInit, Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||||
import { FormService } from './../../../services/form.service';
|
import { FormService } from './../../../services/form.service';
|
||||||
@@ -43,9 +43,11 @@ import { ContainerWidgetComponentModel } from './container.widget.model';
|
|||||||
export class ContainerWidgetComponent extends WidgetComponent implements OnInit, AfterViewInit {
|
export class ContainerWidgetComponent extends WidgetComponent implements OnInit, AfterViewInit {
|
||||||
|
|
||||||
content: ContainerWidgetComponentModel;
|
content: ContainerWidgetComponentModel;
|
||||||
|
numberOfColumns: number;
|
||||||
|
fields: FormFieldModel[];
|
||||||
|
|
||||||
constructor(public formService: FormService) {
|
constructor(public formService: FormService) {
|
||||||
super(formService);
|
super(formService);
|
||||||
}
|
}
|
||||||
|
|
||||||
onExpanderClicked() {
|
onExpanderClicked() {
|
||||||
@@ -57,34 +59,90 @@ export class ContainerWidgetComponent extends WidgetComponent implements OnInit,
|
|||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
if (this.field) {
|
if (this.field) {
|
||||||
this.content = new ContainerWidgetComponentModel(this.field);
|
this.content = new ContainerWidgetComponentModel(this.field);
|
||||||
|
this.getNumberOfColumnsFromTheBiggestBetweenJsonAndColumnsLengthOrOne();
|
||||||
|
this.fields = this.getFields();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getNumberOfColumnsFromTheBiggestBetweenJsonAndColumnsLengthOrOne() {
|
||||||
|
this.numberOfColumns = (this.content.json?.numberOfColumns || 1) > (this.content.columns?.length || 1) ?
|
||||||
|
(this.content.json?.numberOfColumns || 1) :
|
||||||
|
(this.content.columns?.length || 1);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serializes column fields
|
* Serializes column fields
|
||||||
*/
|
*/
|
||||||
get fields(): FormFieldModel[] {
|
private getFields(): FormFieldModel[] {
|
||||||
const fields = [];
|
const { size, rowspanOffset, numberOfColumnElementsToBeProcessedRemaining , fields } = this.initializeHelpers();
|
||||||
|
|
||||||
let rowContainsElement = true,
|
for (let i = 0; i < size; i++) {
|
||||||
rowIndex = 0;
|
let fieldExist = false;
|
||||||
|
let columnIndex = 0;
|
||||||
while (rowContainsElement) {
|
while (columnIndex < this.numberOfColumns) {
|
||||||
rowContainsElement = false;
|
let field: FormFieldModel;
|
||||||
for (let i = 0; i < this.content.columns.length; i++ ) {
|
if (rowspanOffset[columnIndex] > 0) {
|
||||||
const field = this.content.columns[i].fields[rowIndex];
|
this.decreaseRowspanOffsetForColumn(rowspanOffset, columnIndex);
|
||||||
if (field) {
|
} else {
|
||||||
rowContainsElement = true;
|
field = this.getNextFieldToAdd(columnIndex, numberOfColumnElementsToBeProcessedRemaining, field);
|
||||||
|
fields.push(field);
|
||||||
|
if (field) {
|
||||||
|
fieldExist = true;
|
||||||
|
}
|
||||||
|
this.updateColumnsRowspanOffsetWithFieldRowspan(field, rowspanOffset, columnIndex);
|
||||||
|
numberOfColumnElementsToBeProcessedRemaining[columnIndex] = numberOfColumnElementsToBeProcessedRemaining[columnIndex] - 1;
|
||||||
}
|
}
|
||||||
|
columnIndex = columnIndex + (field?.colspan || 1);
|
||||||
fields.push(field);
|
}
|
||||||
|
if (!fieldExist) {
|
||||||
|
i = this.deleteLastEmptyRowAndExit(fields, i, size);
|
||||||
}
|
}
|
||||||
rowIndex++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return fields;
|
return fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private updateColumnsRowspanOffsetWithFieldRowspan(field: FormFieldModel, rowspanOffset: any[], columnIndex: number) {
|
||||||
|
for (let k = 0; k < (field?.colspan || 1); k++) {
|
||||||
|
rowspanOffset[columnIndex + k] = field?.rowspan > 0 ? field?.rowspan - 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getNextFieldToAdd(columnIndex: number, numberOfColumnElementsToBeProcessedRemaining: any[], field: FormFieldModel): FormFieldModel {
|
||||||
|
const rowToCompute = (this.content.columns[columnIndex]?.fields?.length || 0) - numberOfColumnElementsToBeProcessedRemaining[columnIndex];
|
||||||
|
field = this.content.columns[columnIndex]?.fields[rowToCompute];
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
|
||||||
|
private decreaseRowspanOffsetForColumn(rowspanOffset: any[], columnIndex: number) {
|
||||||
|
rowspanOffset[columnIndex] = rowspanOffset[columnIndex] - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private initializeHelpers(): {
|
||||||
|
size: number;
|
||||||
|
rowspanOffset: number[];
|
||||||
|
numberOfColumnElementsToBeProcessedRemaining: number[];
|
||||||
|
fields: FormFieldModel[];
|
||||||
|
} {
|
||||||
|
const fields = [];
|
||||||
|
const numberOfColumnElementsToBeProcessedRemaining: number[] = [];
|
||||||
|
const rowspanOffset: number[] = [];
|
||||||
|
let size = 0;
|
||||||
|
for (let i = 0; i < this.numberOfColumns; i++) {
|
||||||
|
numberOfColumnElementsToBeProcessedRemaining.push(this.content.columns[i]?.fields?.length || 0);
|
||||||
|
rowspanOffset[i] = 0;
|
||||||
|
size += (this.content.columns[i]?.fields?.length || 0);
|
||||||
|
}
|
||||||
|
return { size, rowspanOffset, numberOfColumnElementsToBeProcessedRemaining, fields };
|
||||||
|
}
|
||||||
|
|
||||||
|
private deleteLastEmptyRowAndExit(fields: FormFieldModel[], i: number, size: number) {
|
||||||
|
for (let j = 0; j < this.numberOfColumns; j++) {
|
||||||
|
fields.pop();
|
||||||
|
}
|
||||||
|
i = size;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate the column width based on the numberOfColumns and current field's colspan property
|
* Calculate the column width based on the numberOfColumns and current field's colspan property
|
||||||
*
|
*
|
||||||
|
@@ -152,6 +152,7 @@ export class FormFieldModel extends FormWidgetModel {
|
|||||||
this.restIdProperty = json.restIdProperty;
|
this.restIdProperty = json.restIdProperty;
|
||||||
this.restLabelProperty = json.restLabelProperty;
|
this.restLabelProperty = json.restLabelProperty;
|
||||||
this.colspan = <number> json.colspan;
|
this.colspan = <number> json.colspan;
|
||||||
|
this.rowspan = <number> json.rowspan;
|
||||||
this.minLength = <number> json.minLength || 0;
|
this.minLength = <number> json.minLength || 0;
|
||||||
this.maxLength = <number> json.maxLength || 0;
|
this.maxLength = <number> json.maxLength || 0;
|
||||||
this.minValue = json.minValue;
|
this.minValue = json.minValue;
|
||||||
|
@@ -99,7 +99,7 @@ export class FormModel {
|
|||||||
this.className = json.className || '';
|
this.className = json.className || '';
|
||||||
this.variables = json.variables || [];
|
this.variables = json.variables || [];
|
||||||
this.processVariables = json.processVariables || [];
|
this.processVariables = json.processVariables || [];
|
||||||
this.enableFixedSpace = enableFixedSpace;
|
this.enableFixedSpace = enableFixedSpace || true;
|
||||||
|
|
||||||
const tabCache: FormWidgetModelCache<TabModel> = {};
|
const tabCache: FormWidgetModelCache<TabModel> = {};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user