diff --git a/src/base-interfaces.ts b/src/base-interfaces.ts index 9a01f4a469..6b1470fa0a 100644 --- a/src/base-interfaces.ts +++ b/src/base-interfaces.ts @@ -96,6 +96,7 @@ export interface ISurvey extends ITextProcessor, ISurveyErrorOwner { value: any, displayValue: string ): string; + isGridLayoutMode: boolean; isDisplayMode: boolean; isDesignMode: boolean; areInvisibleElementsShowing: boolean; @@ -292,6 +293,7 @@ export interface IElement extends IConditionRunner, ISurveyElement { clearErrors(): any; dispose(): void; needResponsiveWidth(): boolean; + updateRootStyle(): void; } export interface IQuestion extends IElement, ISurveyErrorOwner { @@ -325,6 +327,7 @@ export interface IPanel extends ISurveyElement, IParentElement { getQuestionStartIndex(): string; getQuestionErrorLocation(): string; getColumsForElement(el: IElement): Array; + updateColumns(): void; parent: IPanel; elementWidthChanged(el: IElement): any; indexOf(el: IElement): number; diff --git a/src/panel.ts b/src/panel.ts index 15d2c6c661..6f60e21281 100644 --- a/src/panel.ts +++ b/src/panel.ts @@ -1,6 +1,6 @@ import { property, propertyArray, Serializer } from "./jsonobject"; import { HashTable, Helpers } from "./helpers"; -import { Base } from "./base"; +import { ArrayChanges, Base } from "./base"; import { ISurveyImpl, IPage, @@ -402,6 +402,9 @@ export class PanelModelBase extends SurveyElement this.updateDescriptionVisibility(this.description); this.markQuestionListDirty(); this.onRowsChanged(); + this.layoutColumns.forEach(col => { + col.onPropertyValueChangedCallback = this.onColumnPropertyValueChangedCallback; + }); } @property({ defaultValue: true }) showTitle: boolean; @@ -1074,6 +1077,22 @@ export class PanelModelBase extends SurveyElement } } } + private onColumnPropertyValueChangedCallback = ( + name: string, + oldValue: any, + newValue: any, + sender: Base, + arrayChanges: ArrayChanges + ) => { + this.updateRootStyle(); + } + public updateColumns() { + this._columns = undefined; + this.updateRootStyle(); + } + public updateRootStyle() { + this.elements?.forEach(el => el.updateRootStyle()); + } public updateCustomWidgets() { for (var i = 0; i < this.elements.length; i++) { this.elements[i].updateCustomWidgets(); @@ -1139,12 +1158,15 @@ export class PanelModelBase extends SurveyElement if (!userDefinedRow && curRowSpan > maxRowColSpan) maxRowColSpan = curRowSpan; }); - const columns = [].concat(this.layoutColumns); + let columns = [].concat(this.layoutColumns); if (maxRowColSpan <= this.layoutColumns.length) { - maxRowColSpan = this.layoutColumns.length; + // maxRowColSpan = this.layoutColumns.length; + columns = this.layoutColumns.slice(0, maxRowColSpan); } else { for (let index = this.layoutColumns.length; index < maxRowColSpan; index++) { - columns.push(new PanelLayoutColumnModel()); + const newCol = new PanelLayoutColumnModel(); + newCol.onPropertyValueChangedCallback = this.onColumnPropertyValueChangedCallback; + columns.push(newCol); } } this._columns = columns; @@ -1166,9 +1188,12 @@ export class PanelModelBase extends SurveyElement } } } + this.layoutColumns = columns; } public getColumsForElement(el: IElement): Array { const row = this.findRowByElement(el); + if (!row || !this.survey || !this.survey.isGridLayoutMode) return []; + const elementIndex = row.elements.indexOf(el); let startIndex = 0; for (let index = 0; index < elementIndex; index++) { @@ -1260,6 +1285,7 @@ export class PanelModelBase extends SurveyElement if (this.isLoadingFromJson) return; this.blockAnimations(); this.setArrayPropertyDirectly("rows", this.buildRows()); + this.updateColumns(); this.releaseAnimations(); } @@ -1435,10 +1461,8 @@ export class PanelModelBase extends SurveyElement } private updateRowsOnElementRemoved(element: IElement) { if (!this.canBuildRows()) return; - this.updateRowsRemoveElementFromRow( - element, - this.findRowByElement(element) - ); + this.updateRowsRemoveElementFromRow(element, this.findRowByElement(element)); + this.updateColumns(); } public updateRowsRemoveElementFromRow( element: IElement, @@ -1637,6 +1661,7 @@ export class PanelModelBase extends SurveyElement if(this.wasRendered) { element.onFirstRendering(); } + this.updateColumns(); return true; } public insertElement(element: IElement, dest?: IElement, location: "bottom" | "top" | "left" | "right" = "bottom"): void { @@ -1747,6 +1772,7 @@ export class PanelModelBase extends SurveyElement return false; } this.elements.splice(index, 1); + this.updateColumns(); return true; } public removeQuestion(question: Question) { diff --git a/src/question.ts b/src/question.ts index bd625014e5..7bd7b4e200 100644 --- a/src/question.ts +++ b/src/question.ts @@ -12,7 +12,7 @@ import { QuestionCustomWidget } from "./questionCustomWidgets"; import { CustomWidgetCollection } from "./questionCustomWidgets"; import { settings } from "./settings"; import { SurveyModel } from "./survey"; -import { PanelModel } from "./panel"; +import { PanelModel, PanelModelBase } from "./panel"; import { RendererFactory } from "./rendererFactory"; import { SurveyError } from "./survey-error"; import { CssClassBuilder } from "./utils/cssClassBuilder"; @@ -121,6 +121,7 @@ export class Question extends SurveyElement public themeChanged(theme: ITheme): void { } @property({ defaultValue: false }) isMobile: boolean; @property() forceIsInputReadOnly: boolean; + @property() colSpan: number; constructor(name: string) { super(name); @@ -174,6 +175,7 @@ export class Question extends SurveyElement this.updateQuestionCss(); }); this.registerPropertyChangedHandlers(["isMobile"], () => { this.onMobileChanged(); }); + this.registerPropertyChangedHandlers(["colSpan"], () => { this.parent?.updateColumns(); }); } protected getDefaultTitle(): string { return this.name; } protected createLocTitleProperty(): LocalizableString { @@ -2734,7 +2736,7 @@ Serializer.addClass("question", [ { name: "width" }, { name: "minWidth", defaultFunc: () => settings.minWidth }, { name: "maxWidth", defaultFunc: () => settings.maxWidth }, - { name: "colSpan:number", default: 1, minValue: 1 }, + { name: "colSpan:number", minValue: 1 }, { name: "startWithNewLine:boolean", default: true, layout: "row" }, { name: "indent:number", default: 0, choices: [0, 1, 2, 3], layout: "row" }, { diff --git a/src/question_custom.ts b/src/question_custom.ts index bc9c2e0eb4..63430c3122 100644 --- a/src/question_custom.ts +++ b/src/question_custom.ts @@ -722,6 +722,7 @@ export abstract class QuestionCustomModelBase extends Question getColumsForElement(el: IElement): Array { return []; } + updateColumns() { } getQuestionStartIndex(): string { return this.getStartIndex(); } diff --git a/src/question_multipletext.ts b/src/question_multipletext.ts index 062b5b7d5b..b80dc83d01 100644 --- a/src/question_multipletext.ts +++ b/src/question_multipletext.ts @@ -817,6 +817,7 @@ export class QuestionMultipleTextModel extends Question getColumsForElement(el: IElement): Array { return []; } + updateColumns() { } getQuestionStartIndex(): string { return this.getStartIndex(); } diff --git a/src/survey-element.ts b/src/survey-element.ts index 9ec0ac9714..cc648fa8a2 100644 --- a/src/survey-element.ts +++ b/src/survey-element.ts @@ -241,6 +241,7 @@ export class SurveyElement extends SurveyElementCore implements ISurvey this.registerPropertyChangedHandlers(["isReadOnly"], () => { this.onReadOnlyChanged(); }); this.registerPropertyChangedHandlers(["errors"], () => { this.updateVisibleErrors(); }); this.registerPropertyChangedHandlers(["isSingleInRow"], () => { this.updateElementCss(false); }); + this.registerPropertyChangedHandlers(["minWidth", "maxWidth", "renderWidth", "allowRootStyle", "parent"], () => { this.updateRootStyle(); }); } protected onPropertyValueChanged(name: string, oldValue: any, newValue: any) { super.onPropertyValueChanged(name, oldValue, newValue); @@ -945,8 +946,9 @@ export class SurveyElement extends SurveyElementCore implements ISurvey } @property({ defaultValue: true }) allowRootStyle: boolean; + @property() rootStyle: any; - get rootStyle() { + public updateRootStyle(): void { let style: { [index: string]: any } = {}; let _width; if (!!this.parent) { @@ -970,7 +972,7 @@ export class SurveyElement extends SurveyElementCore implements ISurvey style["maxWidth"] = this.maxWidth; } } - return style; + this.rootStyle = style; } private isContainsSelection(el: any) { let elementWithSelection: any = undefined; diff --git a/src/survey.ts b/src/survey.ts index 1b83f944cd..661fa38c65 100644 --- a/src/survey.ts +++ b/src/survey.ts @@ -7058,7 +7058,7 @@ export class SurveyModel extends SurveyElementCore public set showTimerPanelMode(val: string) { this.setPropertyValue("showTimerPanelMode", val); } - + @property() isGridLayoutMode: boolean; /** * Specifies how to calculate the survey width. * @@ -8014,6 +8014,7 @@ Serializer.addClass("survey", [ default: "auto", choices: ["auto", "static", "responsive"], }, + { name: "isGridLayoutMode:boolean", default: true, visible: false }, { name: "width", visibleIf: (obj: any) => { return obj.widthMode === "static"; } }, { name: "fitToContainer:boolean", default: true, visible: false }, { name: "headerView", default: "basic", choices: ["basic", "advanced"], visible: false },