(() => {
- return this.isRequired ? this.creator.getLocString("pe.removeRequiredMark") : this.creator.getLocString("pe.markRequired");
- }) as any);
+ };
+ const innerAction = new Action(actionSetup);
+ const requiredAction = new Action(actionSetup);
+ requiredAction.title = this.creator.getLocString("pe.isRequired");
+ requiredAction.innerItem = innerAction;
+ this.updateRequiredAction(requiredAction);
return requiredAction;
}
protected getUpdatedPropertyValue(propName: string, newValue: any): any {
diff --git a/packages/survey-creator-core/src/components/row.ts b/packages/survey-creator-core/src/components/row.ts
index 8178e1679f..6afd19a621 100644
--- a/packages/survey-creator-core/src/components/row.ts
+++ b/packages/survey-creator-core/src/components/row.ts
@@ -17,11 +17,17 @@ export class RowViewModel extends Base {
) {
super();
this.dragTypeOverMe = this.row.dragTypeOverMe;
- this.row.onPropertyChanged.add((s, o) => {
- if (o.name == "dragTypeOverMe") this.dragTypeOverMe = o.newValue;
- });
+ }
+ public subscribeElementChanges() {
+ this.row.onPropertyChanged.add(this.rowDragTypeOverMeChanged);
+ }
+ public unsubscribeElementChanges() {
+ this.row.onPropertyChanged.remove(this.rowDragTypeOverMeChanged);
}
@property() dragTypeOverMe: DragTypeOverMeEnum;
+ private rowDragTypeOverMeChanged: (sender: Base, options: any) => any = (s, o) => {
+ if (o.name == "dragTypeOverMe") this.dragTypeOverMe = o.newValue;
+ };
public get cssClasses() {
let result = "svc-row";
let ghostClass = " svc-row--ghost";
@@ -42,4 +48,9 @@ export class RowViewModel extends Base {
return result;
}
+ public dispose() {
+ super.dispose();
+ this.unsubscribeElementChanges();
+ this.rowDragTypeOverMeChanged = undefined;
+ }
}
diff --git a/packages/survey-creator-core/src/components/tabs/designer-plugin.ts b/packages/survey-creator-core/src/components/tabs/designer-plugin.ts
index d57ed42a51..53a2954c02 100644
--- a/packages/survey-creator-core/src/components/tabs/designer-plugin.ts
+++ b/packages/survey-creator-core/src/components/tabs/designer-plugin.ts
@@ -297,7 +297,9 @@ export class TabDesignerPlugin implements ICreatorPlugin {
this.creator.sidebar.hideSideBarVisibilityControlActions = false;
this.creator.sidebar.sideAreaComponentName = undefined;
this.creator.sidebar.sideAreaComponentData = undefined;
+ this.creator.sidebar.onPropertyChanged.clear();
this.creator.sidebar.header.reset();
+ this.creator.expandCollapseManager.clear();
return true;
}
public onDesignerSurveyPropertyChanged(obj: Base, propName: string): void {
diff --git a/packages/survey-creator-core/src/expand-collapse-manager.ts b/packages/survey-creator-core/src/expand-collapse-manager.ts
index d13b1bba3d..13057e6530 100644
--- a/packages/survey-creator-core/src/expand-collapse-manager.ts
+++ b/packages/survey-creator-core/src/expand-collapse-manager.ts
@@ -27,4 +27,7 @@ export class ExpandCollapseManager {
public remove(adorner: SurveyElementAdornerBase) {
this.adorners.splice(this.adorners.indexOf(adorner), 1);
}
+ public clear() {
+ this.adorners.length = 0;
+ }
}
diff --git a/packages/survey-creator-core/tests/creator-base.tests.ts b/packages/survey-creator-core/tests/creator-base.tests.ts
index 1442ae5e4a..0ea02f3c4e 100644
--- a/packages/survey-creator-core/tests/creator-base.tests.ts
+++ b/packages/survey-creator-core/tests/creator-base.tests.ts
@@ -132,18 +132,22 @@ class PageAdornerTester extends PageAdorner {
this.onPageSelectedCallback && this.onPageSelectedCallback();
}
}
-test("PageAdorner", (): any => {
+test("PageAdorner and selection", (): any => {
const creator = new CreatorTester();
creator.JSON = {
elements: [{ type: "text", name: "question1" }]
};
+ const getSubscriptions = () => (creator.currentPage as any).onPropChangeFunctions.filter(f => f.name == "isSelectedInDesigner");
expect(creator.currentPage.onPropertyChanged.isEmpty).toBeTruthy();
+ expect(getSubscriptions().length == 0).toBeTruthy();
const pageModel = new PageAdornerTester(creator, creator.survey.currentPage);
let counter = 0;
pageModel.onPageSelectedCallback = (): any => {
counter++;
};
- expect(creator.currentPage.onPropertyChanged.isEmpty).toBeFalsy();
+ // expect(creator.currentPage.onPropertyChanged.isEmpty).toBeFalsy();
+ expect(creator.currentPage.onPropertyChanged.isEmpty).toBeTruthy();
+ expect(getSubscriptions().length == 0).toBeFalsy();
expect(pageModel.isSelected).toBeFalsy();
creator.selectElement(creator.survey.getQuestionByName("question1"));
expect(pageModel.isSelected).toBeFalsy();
@@ -156,6 +160,7 @@ test("PageAdorner", (): any => {
expect(counter).toEqual(1);
pageModel.dispose();
expect(creator.currentPage.onPropertyChanged.isEmpty).toBeTruthy();
+ expect(getSubscriptions().length == 0).toBeTruthy();
});
test("PageAdorner - remove page if: it is the last page, there is no elements and there is no properties set", (): any => {
const creator = new CreatorTester();
diff --git a/packages/survey-creator-core/tests/question-adorner.tests.ts b/packages/survey-creator-core/tests/question-adorner.tests.ts
index 64a29ed0e1..51a2f0166f 100644
--- a/packages/survey-creator-core/tests/question-adorner.tests.ts
+++ b/packages/survey-creator-core/tests/question-adorner.tests.ts
@@ -28,7 +28,8 @@ test("Check required action", (): any => {
expect(requiredAction.active).toBe(false);
expect(requiredAction.title).toBe("Required");
- const requiredActionInPopup = new Action(requiredAction.innerItem);
+ const requiredActionInPopup = requiredAction.innerItem;
+ expect(requiredActionInPopup instanceof Action).toBeTruthy();
expect(requiredActionInPopup.title).toBe("Mark as required");
question.isRequired = true;
expect(requiredActionInPopup.title).toBe("Remove the required mark");
diff --git a/packages/survey-creator-knockout/src/row.ts b/packages/survey-creator-knockout/src/row.ts
index 753c5616de..5e7611c3d0 100644
--- a/packages/survey-creator-knockout/src/row.ts
+++ b/packages/survey-creator-knockout/src/row.ts
@@ -22,6 +22,7 @@ class KnockoutRowViewModel extends RowViewModel {
public templateData: any
) {
super(creator, row, templateData);
+ this.subscribeElementChanges();
}
}
diff --git a/packages/survey-creator-knockout/src/toolbox/adaptive-toolbox.ts b/packages/survey-creator-knockout/src/toolbox/adaptive-toolbox.ts
index 27dac967b0..7d3545f77c 100644
--- a/packages/survey-creator-knockout/src/toolbox/adaptive-toolbox.ts
+++ b/packages/survey-creator-knockout/src/toolbox/adaptive-toolbox.ts
@@ -13,6 +13,7 @@ ko.components.register("svc-adaptive-toolbox", {
ko.utils.domNodeDisposal.addDisposeCallback(componentInfo.element, () => {
manager.dispose();
model.toolbox.unsubscribeRootElement();
+ model.toolbox.setRootElement(undefined);
model.dispose();
});
return model;
diff --git a/packages/survey-creator-react/src/adorners/QuestionFooter.tsx b/packages/survey-creator-react/src/adorners/QuestionFooter.tsx
index 02358c6b9b..e567ec9811 100644
--- a/packages/survey-creator-react/src/adorners/QuestionFooter.tsx
+++ b/packages/survey-creator-react/src/adorners/QuestionFooter.tsx
@@ -1,15 +1,9 @@
import { QuestionAdornerViewModel, toggleHovered } from "survey-creator-core";
import * as React from "react";
import { ReactDragEvent, ReactMouseEvent } from "../events";
-import { Base, Question } from "survey-core";
import {
SurveyActionBar,
ReactElementFactory,
- SurveyElementBase,
- SurveyQuestion,
- attachKey2click,
- SvgIcon,
- Popup
} from "survey-react-ui";
export interface QuestionWrapperFooterProps {
diff --git a/packages/survey-creator-react/src/adorners/Row.tsx b/packages/survey-creator-react/src/adorners/Row.tsx
index fa3cf7e81f..2d5a064510 100644
--- a/packages/survey-creator-react/src/adorners/Row.tsx
+++ b/packages/survey-creator-react/src/adorners/Row.tsx
@@ -19,6 +19,9 @@ export class RowWrapper extends CreatorModelElement<
super(props);
}
protected createModel(props: any): void {
+ if (!!this.model) {
+ this.model.dispose();
+ }
this.model = new RowViewModel(
props.componentData.creator,
props.row,
@@ -32,6 +35,15 @@ export class RowWrapper extends CreatorModelElement<
return this.model;
}
+ componentDidMount(): void {
+ super.componentDidMount();
+ this.model.subscribeElementChanges();
+ }
+ componentWillUnmount(): void {
+ this.model.unsubscribeElementChanges();
+ super.componentWillUnmount();
+ }
+
render(): JSX.Element {
return (
{
+ model.value && model.value.subscribeElementChanges();
+});
+onUnmounted(() => {
+ model.value && model.value.unsubscribeElementChanges();
+});
+
diff --git a/packages/survey-creator-vue/src/toolbox/AdaptiveToolbox.vue b/packages/survey-creator-vue/src/toolbox/AdaptiveToolbox.vue
index 4cc151013e..ea1e363381 100644
--- a/packages/survey-creator-vue/src/toolbox/AdaptiveToolbox.vue
+++ b/packages/survey-creator-vue/src/toolbox/AdaptiveToolbox.vue
@@ -94,6 +94,7 @@ onMounted(() => {
});
onUnmounted(() => {
responsivityManager?.dispose();
+ toolbox.value.setRootElement(undefined as any);
toolbox.value.unsubscribeRootElement();
});
const renderedActions = computed(() => toolbox.value.renderedActions);
diff --git a/visualRegressionTests-V2/tests/designer/surface.ts b/visualRegressionTests-V2/tests/designer/surface.ts
index 7537f7c6cc..57c2ac3912 100644
--- a/visualRegressionTests-V2/tests/designer/surface.ts
+++ b/visualRegressionTests-V2/tests/designer/surface.ts
@@ -68,7 +68,7 @@ test("Test question type converter", async (t) => {
await takeElementScreenshot("convert-to-popup.png", Selector(".sv-popup__container").filterVisible(), t, comparer);
});
});
-test("Test question type converter on page for panel", async (t) => {
+test("Test question type converter on page for panel - 1", async (t) => {
await wrapVisualTest(t, async (t, comparer) => {
await t.resizeWindow(1000, 800);
@@ -97,7 +97,7 @@ test("Test question type converter on page for panel", async (t) => {
});
});
-test("Test question type converter on page for panel", async (t) => {
+test("Test question type converter on page for panel - 2", async (t) => {
await wrapVisualTest(t, async (t, comparer) => {
await t.resizeWindow(1000, 800);
diff --git a/visualRegressionTests/tests/designer/etalons/convert-to-popup-panel.png b/visualRegressionTests/tests/designer/etalons/convert-to-popup-panel.png
index aa4f9b7f06..5cf9d83062 100644
Binary files a/visualRegressionTests/tests/designer/etalons/convert-to-popup-panel.png and b/visualRegressionTests/tests/designer/etalons/convert-to-popup-panel.png differ
diff --git a/visualRegressionTests/tests/designer/etalons/convert-to-popup-panel_mask.png b/visualRegressionTests/tests/designer/etalons/convert-to-popup-panel_mask.png
new file mode 100644
index 0000000000..c16b6f77d4
Binary files /dev/null and b/visualRegressionTests/tests/designer/etalons/convert-to-popup-panel_mask.png differ
diff --git a/visualRegressionTests/tests/designer/surface.ts b/visualRegressionTests/tests/designer/surface.ts
index 7ca790cc37..953881d058 100644
--- a/visualRegressionTests/tests/designer/surface.ts
+++ b/visualRegressionTests/tests/designer/surface.ts
@@ -68,7 +68,7 @@ test("Test question type converter", async (t) => {
await takeElementScreenshot("convert-to-popup.png", Selector(".sv-popup__container").filterVisible(), t, comparer);
});
});
-test("Test question type converter on page for panel", async (t) => {
+test("Test question type converter on page for panel - 1", async (t) => {
await wrapVisualTest(t, async (t, comparer) => {
await t.resizeWindow(1000, 800);
@@ -97,7 +97,7 @@ test("Test question type converter on page for panel", async (t) => {
});
});
-test("Test question type converter on page for panel", async (t) => {
+test("Test question type converter on page for panel - 2", async (t) => {
await wrapVisualTest(t, async (t, comparer) => {
await t.resizeWindow(1000, 800);