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);
|
||||
fixture.detectChanges();
|
||||
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);
|
||||
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) => {
|
||||
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');
|
||||
expect(fullWidthElement.style['width']).toBe('100%');
|
||||
const fullWidthElement = fixture.nativeElement.querySelector('#field-d52ada4e-cbdc-4f0c-a480-5b85fa00e4f8-container div.adf-grid-list .adf-grid-list-item');
|
||||
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 () => {
|
||||
|
@@ -12,11 +12,13 @@
|
||||
</div>
|
||||
|
||||
<div *ngIf="field?.form?.enableFixedSpace else fixingTemplate">
|
||||
<section class="adf-grid-list" *ngIf="content?.isExpanded">
|
||||
<div class="adf-grid-list-item" *ngFor="let field of fields" [style.width.%]="getColumnWith(field)">
|
||||
<div class="adf-grid-list" [ngStyle]="{ 'grid-template-columns': 'repeat('+numberOfColumns+', 1fr)'}"
|
||||
*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>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-template #fixingTemplate>
|
||||
@@ -28,5 +30,3 @@
|
||||
</div>
|
||||
</section>
|
||||
</ng-template>
|
||||
|
||||
|
||||
|
@@ -57,14 +57,10 @@
|
||||
}
|
||||
|
||||
.adf-grid-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-left: -1%;
|
||||
margin-right: -1%;
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.adf-grid-list-item {
|
||||
flex-grow: 1;
|
||||
box-sizing: border-box;
|
||||
padding-left: 1%;
|
||||
padding-right: 1%;
|
||||
@@ -119,5 +115,9 @@
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
adf-form-field {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -17,7 +17,6 @@
|
||||
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ContainerColumnModel } from './../core/container-column.model';
|
||||
import { FormFieldTypes } from './../core/form-field-types';
|
||||
import { FormFieldModel } from './../core/form-field.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) => {
|
||||
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) => {
|
||||
expect(field).not.toBe(null);
|
||||
expect(field.id).toBe('fakeField');
|
||||
@@ -117,30 +116,22 @@ describe('ContainerWidgetComponent', () => {
|
||||
describe('fields', () => {
|
||||
|
||||
it('should serializes the content fields', () => {
|
||||
const field1 = <FormFieldModel> {id: '1'},
|
||||
field2 = <FormFieldModel> {id: '2'},
|
||||
field3 = <FormFieldModel> {id: '3'},
|
||||
field4 = <FormFieldModel> {id: '4'},
|
||||
field5 = <FormFieldModel> {id: '5'},
|
||||
field6 = <FormFieldModel> {id: '6'};
|
||||
const form = new FormModel();
|
||||
const json = {
|
||||
id: 'test',
|
||||
name: 'test',
|
||||
type: 'container',
|
||||
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()));
|
||||
container.columns = [
|
||||
<ContainerColumnModel> { fields: [
|
||||
field1,
|
||||
field2,
|
||||
field3
|
||||
] },
|
||||
<ContainerColumnModel> { fields: [
|
||||
field4,
|
||||
field5
|
||||
] },
|
||||
<ContainerColumnModel> { fields: [
|
||||
field6
|
||||
] }
|
||||
];
|
||||
|
||||
widget.content = container;
|
||||
const field = new FormFieldModel(form, json);
|
||||
widget.field = field;
|
||||
widget.ngOnInit();
|
||||
|
||||
expect(widget.fields[0].id).toEqual('1');
|
||||
expect(widget.fields[1].id).toEqual('4');
|
||||
@@ -152,6 +143,99 @@ describe('ContainerWidgetComponent', () => {
|
||||
expect(widget.fields[7]).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', () => {
|
||||
|
@@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* tslint:disable:component-selector */
|
||||
/* tslint:disable:component-selector */
|
||||
|
||||
import { AfterViewInit, Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { FormService } from './../../../services/form.service';
|
||||
@@ -43,9 +43,11 @@ import { ContainerWidgetComponentModel } from './container.widget.model';
|
||||
export class ContainerWidgetComponent extends WidgetComponent implements OnInit, AfterViewInit {
|
||||
|
||||
content: ContainerWidgetComponentModel;
|
||||
numberOfColumns: number;
|
||||
fields: FormFieldModel[];
|
||||
|
||||
constructor(public formService: FormService) {
|
||||
super(formService);
|
||||
super(formService);
|
||||
}
|
||||
|
||||
onExpanderClicked() {
|
||||
@@ -57,34 +59,90 @@ export class ContainerWidgetComponent extends WidgetComponent implements OnInit,
|
||||
ngOnInit() {
|
||||
if (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
|
||||
*/
|
||||
get fields(): FormFieldModel[] {
|
||||
const fields = [];
|
||||
private getFields(): FormFieldModel[] {
|
||||
const { size, rowspanOffset, numberOfColumnElementsToBeProcessedRemaining , fields } = this.initializeHelpers();
|
||||
|
||||
let rowContainsElement = true,
|
||||
rowIndex = 0;
|
||||
|
||||
while (rowContainsElement) {
|
||||
rowContainsElement = false;
|
||||
for (let i = 0; i < this.content.columns.length; i++ ) {
|
||||
const field = this.content.columns[i].fields[rowIndex];
|
||||
if (field) {
|
||||
rowContainsElement = true;
|
||||
for (let i = 0; i < size; i++) {
|
||||
let fieldExist = false;
|
||||
let columnIndex = 0;
|
||||
while (columnIndex < this.numberOfColumns) {
|
||||
let field: FormFieldModel;
|
||||
if (rowspanOffset[columnIndex] > 0) {
|
||||
this.decreaseRowspanOffsetForColumn(rowspanOffset, columnIndex);
|
||||
} else {
|
||||
field = this.getNextFieldToAdd(columnIndex, numberOfColumnElementsToBeProcessedRemaining, field);
|
||||
fields.push(field);
|
||||
if (field) {
|
||||
fieldExist = true;
|
||||
}
|
||||
this.updateColumnsRowspanOffsetWithFieldRowspan(field, rowspanOffset, columnIndex);
|
||||
numberOfColumnElementsToBeProcessedRemaining[columnIndex] = numberOfColumnElementsToBeProcessedRemaining[columnIndex] - 1;
|
||||
}
|
||||
|
||||
fields.push(field);
|
||||
columnIndex = columnIndex + (field?.colspan || 1);
|
||||
}
|
||||
if (!fieldExist) {
|
||||
i = this.deleteLastEmptyRowAndExit(fields, i, size);
|
||||
}
|
||||
rowIndex++;
|
||||
}
|
||||
|
||||
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
|
||||
*
|
||||
|
@@ -152,6 +152,7 @@ export class FormFieldModel extends FormWidgetModel {
|
||||
this.restIdProperty = json.restIdProperty;
|
||||
this.restLabelProperty = json.restLabelProperty;
|
||||
this.colspan = <number> json.colspan;
|
||||
this.rowspan = <number> json.rowspan;
|
||||
this.minLength = <number> json.minLength || 0;
|
||||
this.maxLength = <number> json.maxLength || 0;
|
||||
this.minValue = json.minValue;
|
||||
|
@@ -99,7 +99,7 @@ export class FormModel {
|
||||
this.className = json.className || '';
|
||||
this.variables = json.variables || [];
|
||||
this.processVariables = json.processVariables || [];
|
||||
this.enableFixedSpace = enableFixedSpace;
|
||||
this.enableFixedSpace = enableFixedSpace || true;
|
||||
|
||||
const tabCache: FormWidgetModelCache<TabModel> = {};
|
||||
|
||||
|
Reference in New Issue
Block a user