Skip to content

Commit

Permalink
Grid layout (#9194)
Browse files Browse the repository at this point in the history
* rename layoutColumns -> gridLayoutColumns

* Fix grid layout for simpler cases - "3 - 2" layout

* grid layout: fix round column width

* grid layout: fix adaptivity

* grid layout: fix adaptivity

* grid layout: update markup snapshots

* grid layout: revert some changes (function lcm)

* grid layout: revert some changes

---------

Co-authored-by: OlgaLarina <[email protected]>
  • Loading branch information
OlgaLarina and OlgaLarina authored Dec 24, 2024
1 parent c51b700 commit 5575253
Show file tree
Hide file tree
Showing 9 changed files with 247 additions and 101 deletions.
38 changes: 22 additions & 16 deletions packages/survey-core/src/panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { ElementFactory, QuestionFactory } from "./questionfactory";
import { LocalizableString } from "./localizablestring";
import { OneAnswerRequiredError } from "./error";
import { settings } from "./settings";
import { cleanHtmlElementAfterAnimation, findScrollableParent, getElementWidth, isElementVisible, roundTo2Decimals, prepareElementForVerticalAnimation, setPropertiesOnElementForAnimation } from "./utils/utils";
import { cleanHtmlElementAfterAnimation, findScrollableParent, getElementWidth, isElementVisible, floorTo2Decimals, prepareElementForVerticalAnimation, setPropertiesOnElementForAnimation } from "./utils/utils";
import { SurveyError } from "./survey-error";
import { CssClassBuilder } from "./utils/cssClassBuilder";
import { IAction } from "./actions/action";
Expand Down Expand Up @@ -311,7 +311,7 @@ export class PanelModelBase extends SurveyElement<Question>
private _columns: Array<PanelLayoutColumnModel> = undefined;
private _columnsReady = false;

@propertyArray() layoutColumns: Array<PanelLayoutColumnModel>;
@propertyArray() gridLayoutColumns: Array<PanelLayoutColumnModel>;

addElementCallback: (element: IElement) => void;
removeElementCallback: (element: IElement) => void;
Expand All @@ -329,7 +329,8 @@ export class PanelModelBase extends SurveyElement<Question>
isAnimationEnabled: () => this.animationAllowed,
getAnimatedElement: (row: QuestionRowModel) => row.getRootElement(),
getLeaveOptions: (row: QuestionRowModel, info) => {
return { cssClass: this.cssClasses.rowLeave,
return {
cssClass: this.cssClasses.rowLeave,
onBeforeRunAnimation: prepareElementForVerticalAnimation,
onAfterRunAnimation: cleanHtmlElementAfterAnimation,

Expand Down Expand Up @@ -419,7 +420,7 @@ export class PanelModelBase extends SurveyElement<Question>
this.updateDescriptionVisibility(this.description);
this.markQuestionListDirty();
this.onRowsChanged();
this.layoutColumns.forEach(col => {
this.gridLayoutColumns.forEach(col => {
col.onPropertyValueChangedCallback = this.onColumnPropertyValueChangedCallback;
});
}
Expand Down Expand Up @@ -1142,7 +1143,6 @@ export class PanelModelBase extends SurveyElement<Question>
}
curRowSpan += (el.colSpan || 1);
});

if (!userDefinedRow && curRowSpan > maxRowColSpan) maxRowColSpan = curRowSpan;
});
return maxRowColSpan;
Expand All @@ -1158,7 +1158,7 @@ export class PanelModelBase extends SurveyElement<Question>
}
});
if (!!remainingColCount) {
const oneColumnWidth = roundTo2Decimals((100 - remainingSpace) / remainingColCount);
const oneColumnWidth = floorTo2Decimals((100 - remainingSpace) / remainingColCount);
for (let index = 0; index < columns.length; index++) {
if (!columns[index].width) {
columns[index].setPropertyValue("effectiveWidth", oneColumnWidth);
Expand All @@ -1174,7 +1174,7 @@ export class PanelModelBase extends SurveyElement<Question>
arrayChanges: ArrayChanges
) => {
if (this._columnsReady) {
this.updateColumnWidth(this.layoutColumns);
this.updateColumnWidth(this.gridLayoutColumns);
this.updateRootStyle();
}
}
Expand Down Expand Up @@ -1253,11 +1253,11 @@ export class PanelModelBase extends SurveyElement<Question>
}
protected generateColumns(): void {
let maxRowColSpan = this.calcMaxRowColSpan();
let columns = [].concat(this.layoutColumns);
if (maxRowColSpan <= this.layoutColumns.length) {
columns = this.layoutColumns.slice(0, maxRowColSpan);
let columns = [].concat(this.gridLayoutColumns);
if (maxRowColSpan <= this.gridLayoutColumns.length) {
columns = this.gridLayoutColumns.slice(0, maxRowColSpan);
} else {
for (let index = this.layoutColumns.length; index < maxRowColSpan; index++) {
for (let index = this.gridLayoutColumns.length; index < maxRowColSpan; index++) {
const newCol = new PanelLayoutColumnModel();
newCol.onPropertyValueChangedCallback = this.onColumnPropertyValueChangedCallback;
columns.push(newCol);
Expand All @@ -1271,7 +1271,13 @@ export class PanelModelBase extends SurveyElement<Question>
finally {
this._columnsReady = true;
}
this.layoutColumns = columns;
this.gridLayoutColumns = columns;
}
public updateGridColumns(): void {
this.updateColumns();
this.elements.forEach(el => {
el.isPanel && (<any>el as PanelModelBase).updateGridColumns();
});
}
public getColumsForElement(el: IElement): Array<PanelLayoutColumnModel> {
const row = this.findRowByElement(el);
Expand Down Expand Up @@ -2027,13 +2033,13 @@ export class PanelModelBase extends SurveyElement<Question>

public getSerializableColumnsValue(): Array<PanelLayoutColumnModel> {
let tailIndex = -1;
for (let index = this.layoutColumns.length - 1; index >= 0; index--) {
if (!this.layoutColumns[index].isEmpty()) {
for (let index = this.gridLayoutColumns.length - 1; index >= 0; index--) {
if (!this.gridLayoutColumns[index].isEmpty()) {
tailIndex = index;
break;
}
}
return this.layoutColumns.slice(0, tailIndex + 1);
return this.gridLayoutColumns.slice(0, tailIndex + 1);
}
public afterRender(el: HTMLElement): void {
this.afterRenderCore(el);
Expand Down Expand Up @@ -2450,7 +2456,7 @@ Serializer.addClass(
choices: ["default", "top", "bottom", "left", "hidden"],
},
{
name: "layoutColumns:panellayoutcolumns",
name: "gridLayoutColumns:panellayoutcolumns",
className: "panellayoutcolumn", isArray: true,
onSerializeValue: (obj: any): any => { return obj.getSerializableColumnsValue(); },
visibleIf: function (obj: any) { return !!obj && !!obj.survey && obj.survey.gridLayoutEnabled; }
Expand Down
4 changes: 2 additions & 2 deletions packages/survey-core/src/survey-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1061,11 +1061,11 @@ export class SurveyElement<E = any> extends SurveyElementCore implements ISurvey
const columns = this.parent.getColumsForElement(this as any);
_width = columns.reduce((sum, col) => col.effectiveWidth + sum, 0);
if (!!_width && _width !== 100) {
style["flexGrow"] = 0;
style["flexGrow"] = 1;
style["flexShrink"] = 0;
style["flexBasis"] = _width + "%";
style["minWidth"] = undefined;
style["maxWidth"] = undefined;
style["maxWidth"] = this.maxWidth;
}
}
if (Object.keys(style).length == 0) {
Expand Down
9 changes: 8 additions & 1 deletion packages/survey-core/src/survey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7318,7 +7318,14 @@ export class SurveyModel extends SurveyElementCore
public set showTimerPanelMode(val: string) {
this.timerInfoMode = this.getTimerInfoVal(val);
}
@property() gridLayoutEnabled: boolean;
@property({
onSet: (newValue: boolean, target: SurveyModel) => {
target.updateGridColumns();
}
}) gridLayoutEnabled: boolean;
public updateGridColumns(): void {
this.pages.forEach(page => page.updateGridColumns());
}
/**
* Specifies how to calculate the survey width.
*
Expand Down
4 changes: 2 additions & 2 deletions packages/survey-core/src/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -812,8 +812,8 @@ export function cleanHtmlElementAfterAnimation(el: HTMLElement): void {
delete (el as any)["__sv_created_properties"];
}
}
export function roundTo2Decimals(number: number): number {
return Math.round(number * 100) / 100;
export function floorTo2Decimals(number: number): number {
return Math.floor(number * 100) / 100;
}

export {
Expand Down
Loading

0 comments on commit 5575253

Please sign in to comment.