From d0a7a8bf7faf87b502e8655844dd9d6a66cf63a9 Mon Sep 17 00:00:00 2001 From: Andrew Telnov Date: Fri, 1 Nov 2024 21:55:07 +0200 Subject: [PATCH 1/4] Reduce the number of survey fromJSON/toJSON to 1 on switching from Editor (JSON) tab to Designer tab --- .../src/components/tabs/designer-plugin.ts | 3 +-- .../src/components/tabs/json-editor-plugin.ts | 9 ++----- .../src/components/tabs/logic-plugin.ts | 3 +-- .../src/components/tabs/test-plugin.ts | 3 +-- .../src/components/tabs/theme-plugin.ts | 3 +-- .../src/components/tabs/translation-plugin.ts | 4 +-- .../survey-creator-core/src/creator-base.ts | 25 ++++++++++++------- .../src/creator-settings.ts | 2 +- .../src/plugins/undo-redo/index.ts | 10 +++----- .../survey-creator-core/src/textWorker.ts | 4 +++ .../tests/tabs/json-editor.tests.ts | 18 ++++++++++++- 11 files changed, 48 insertions(+), 36 deletions(-) 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 140a44d35d..9583cd4041 100644 --- a/packages/survey-creator-core/src/components/tabs/designer-plugin.ts +++ b/packages/survey-creator-core/src/components/tabs/designer-plugin.ts @@ -278,7 +278,7 @@ export class TabDesignerPlugin implements ICreatorPlugin { this.creator.focusElement(undefined, true); } - public deactivate(): boolean { + public deactivate(): void { if (this.model) { this.model.dispose(); } @@ -291,7 +291,6 @@ export class TabDesignerPlugin implements ICreatorPlugin { this.creator.sidebar.sideAreaComponentName = undefined; this.creator.sidebar.sideAreaComponentData = undefined; this.creator.sidebar.header.reset(); - return true; } public onDesignerSurveyPropertyChanged(obj: Base, propName: string): void { if (!!this.model) { diff --git a/packages/survey-creator-core/src/components/tabs/json-editor-plugin.ts b/packages/survey-creator-core/src/components/tabs/json-editor-plugin.ts index 0659c4393a..72f33e0b0b 100644 --- a/packages/survey-creator-core/src/components/tabs/json-editor-plugin.ts +++ b/packages/survey-creator-core/src/components/tabs/json-editor-plugin.ts @@ -220,22 +220,17 @@ export abstract class TabJsonEditorBasePlugin implements ICreatorPlugin { public activate(): void { this.model = this.createModel(this.creator); } - public deactivate(): boolean { + public deactivate(): void { if (this.model) { - const textWorker: SurveyTextWorker = new SurveyTextWorker(this.model.text); - if (!textWorker.isJsonCorrect) { - return false; - } if (!this.model.readOnly && this.model.isJSONChanged) { this.creator.selectedElement = undefined; - this.creator.text = this.model.text; + this.creator.changeText(this.model.text, false, true); this.creator.selectedElement = this.creator.survey; this.creator.setModified({ type: "JSON_EDITOR" }); } this.model.dispose(); this.model = undefined; } - return true; } public defaultAllowingDeactivate(): boolean { if (!this.model) return true; diff --git a/packages/survey-creator-core/src/components/tabs/logic-plugin.ts b/packages/survey-creator-core/src/components/tabs/logic-plugin.ts index a05636f04b..e348675a40 100644 --- a/packages/survey-creator-core/src/components/tabs/logic-plugin.ts +++ b/packages/survey-creator-core/src/components/tabs/logic-plugin.ts @@ -71,9 +71,8 @@ export class TabLogicPlugin implements ICreatorPlugin { } onSuccess(); } - public deactivate(): boolean { + public deactivate(): void { this.disposeObjs(); - return true; } public dispose(): void { this.disposeObjs(); diff --git a/packages/survey-creator-core/src/components/tabs/test-plugin.ts b/packages/survey-creator-core/src/components/tabs/test-plugin.ts index cf9f5153f5..92ef41b650 100644 --- a/packages/survey-creator-core/src/components/tabs/test-plugin.ts +++ b/packages/survey-creator-core/src/components/tabs/test-plugin.ts @@ -105,7 +105,7 @@ export class TabTestPlugin implements ICreatorPlugin { } }); } - public deactivate(): boolean { + public deactivate(): void { if (this.model) { this.simulatorTheme = this.model.simulator.survey.css; this.model.onSurveyCreatedCallback = undefined; @@ -115,7 +115,6 @@ export class TabTestPlugin implements ICreatorPlugin { this.languageSelectorAction.visible = false; this.testAgainAction.visible = false; this.invisibleToggleAction && (this.invisibleToggleAction.visible = false); - return true; } private getAvailableThemes(themeMapper: Array): Array { const availableThemesToItems = []; diff --git a/packages/survey-creator-core/src/components/tabs/theme-plugin.ts b/packages/survey-creator-core/src/components/tabs/theme-plugin.ts index 537946e9e7..37f8e08a95 100644 --- a/packages/survey-creator-core/src/components/tabs/theme-plugin.ts +++ b/packages/survey-creator-core/src/components/tabs/theme-plugin.ts @@ -451,7 +451,7 @@ export class ThemeTabPlugin implements ICreatorPlugin { } }); } - public deactivate(): boolean { + public deactivate(): void { if (this.model) { this.simulatorCssClasses = this.model.survey.css; this.model.onPropertyChanged.clear(); @@ -470,7 +470,6 @@ export class ThemeTabPlugin implements ICreatorPlugin { this.propertyGridTab.visible = false; this.testAgainAction.visible = false; this.invisibleToggleAction && (this.invisibleToggleAction.visible = false); - return true; } public saveToFileHandler = saveToFileHandler; diff --git a/packages/survey-creator-core/src/components/tabs/translation-plugin.ts b/packages/survey-creator-core/src/components/tabs/translation-plugin.ts index 2447a3d9ee..e867beccfb 100644 --- a/packages/survey-creator-core/src/components/tabs/translation-plugin.ts +++ b/packages/survey-creator-core/src/components/tabs/translation-plugin.ts @@ -91,7 +91,7 @@ export class TabTranslationPlugin implements ICreatorPlugin { this.model.filteredPage = null; this.updateFilterPageAction(true); } - public deactivate(): boolean { + public deactivate(): void { if (!!this.model) { this.model.dispose(); } @@ -104,8 +104,6 @@ export class TabTranslationPlugin implements ICreatorPlugin { this.mergeLocaleWithDefaultAction.visible = false; this.importCsvAction.visible = false; this.exportCsvAction.visible = false; - - return true; } private createMergeLocaleWithDefaultActionTitleUpdater(): any { return new ComputedUpdater(() => { diff --git a/packages/survey-creator-core/src/creator-base.ts b/packages/survey-creator-core/src/creator-base.ts index 75a18309d3..4e8f873e6d 100644 --- a/packages/survey-creator-core/src/creator-base.ts +++ b/packages/survey-creator-core/src/creator-base.ts @@ -1197,16 +1197,14 @@ export class SurveyCreatorModel extends Base const chaningOptions = { tabName: viewName, allow: allow, model: this.currentPlugin?.model }; this.onActiveTabChanging.fire(this, chaningOptions); if (!chaningOptions.allow) return; - if (!this.canSwitchViewType()) return false; + if(!!this.currentPlugin && this.currentPlugin.deactivate) { + this.currentPlugin.deactivate(); + } const plugin = this.activatePlugin(viewName); this.viewType = viewName; this.onActiveTabChanged.fire(this, { tabName: viewName, plugin: plugin, model: !!plugin ? plugin.model : undefined }); return true; } - private canSwitchViewType(): boolean { - const plugin: ICreatorPlugin = this.currentPlugin; - return !plugin || !plugin.deactivate || plugin.deactivate(); - } private activatePlugin(newType: string): ICreatorPlugin { const plugin: ICreatorPlugin = this.getPlugin(newType); if (!!plugin) { @@ -2137,14 +2135,23 @@ export class SurveyCreatorModel extends Base } } - public changeText(value: string, clearState = false): void { + public changeText(value: string, clearState = false, trustJSON?: boolean): void { this.setTextValue(value); if (!value) { this.initSurveyWithJSON(undefined, clearState); } else { - const textWorker = new SurveyTextWorker(value); - if (textWorker.isJsonCorrect || !!textWorker.survey) { - this.initSurveyWithJSON(textWorker.survey.toJSON(), clearState); + let jsonText = trustJSON ? value : undefined; + if(!trustJSON) { + const textWorker = new SurveyTextWorker(value); + if(textWorker.isJsonCorrect) { + jsonText = value; + } + else if(!!textWorker.survey) { + jsonText = textWorker.survey.toJSON(); + } + } + if (!!jsonText) { + this.initSurveyWithJSON(jsonText, clearState); } else { this.viewType = "editor"; } diff --git a/packages/survey-creator-core/src/creator-settings.ts b/packages/survey-creator-core/src/creator-settings.ts index 7acc202686..25d30d265c 100644 --- a/packages/survey-creator-core/src/creator-settings.ts +++ b/packages/survey-creator-core/src/creator-settings.ts @@ -189,7 +189,7 @@ export interface ICollectionItemAllowOperations { export interface ICreatorPlugin { activate: () => void; update?: () => void; - deactivate?: () => boolean; + deactivate?: () => void; canDeactivateAsync?: (onSuccess: () => void) => void; defaultAllowingDeactivate?: () => boolean | undefined; dispose?: () => void; diff --git a/packages/survey-creator-core/src/plugins/undo-redo/index.ts b/packages/survey-creator-core/src/plugins/undo-redo/index.ts index b9e217d6dd..6d7cbf8c75 100644 --- a/packages/survey-creator-core/src/plugins/undo-redo/index.ts +++ b/packages/survey-creator-core/src/plugins/undo-redo/index.ts @@ -33,13 +33,9 @@ export class UndoRedoPlugin implements ICreatorPlugin { }); } public model: any = undefined; - public activate(): void { - } - public deactivate(): boolean { - return true; - } - public update(): void { - } + public activate(): void {} + public deactivate(): void {} + public update(): void {} public addFooterActions() { this.model.undoAction && (this.creator.footerToolbar.actions.splice(2, 0, this.model.undoAction)); this.model.redoAction && (this.creator.footerToolbar.actions.splice(3, 0, this.model.redoAction)); diff --git a/packages/survey-creator-core/src/textWorker.ts b/packages/survey-creator-core/src/textWorker.ts index 955571cc21..c1988e4acd 100644 --- a/packages/survey-creator-core/src/textWorker.ts +++ b/packages/survey-creator-core/src/textWorker.ts @@ -169,6 +169,7 @@ export class SurveyTextWorkerJsonError extends SurveyTextWorkerError { } export class SurveyTextWorker { + public static onProcessJson: ((json: any) => void) | undefined; public static newLineChar: string = "\n"; public errors: Array; private surveyValue: SurveyModel; @@ -198,6 +199,9 @@ export class SurveyTextWorker { } if (this.jsonValue != null) { this.updateJsonPositions(this.jsonValue); + if(!!SurveyTextWorker.onProcessJson) { + SurveyTextWorker.onProcessJson(this.jsonValue); + } this.surveyValue = new SurveyForTextWorker(this.jsonValue); const jsonErrors = this.surveyValue.jsonErrors; if (Array.isArray(jsonErrors)) { diff --git a/packages/survey-creator-core/tests/tabs/json-editor.tests.ts b/packages/survey-creator-core/tests/tabs/json-editor.tests.ts index 88a2846d60..827ad91da4 100644 --- a/packages/survey-creator-core/tests/tabs/json-editor.tests.ts +++ b/packages/survey-creator-core/tests/tabs/json-editor.tests.ts @@ -1,7 +1,7 @@ import { TabJsonEditorTextareaPlugin, TextareaJsonEditorModel } from "../../src/components/tabs/json-editor-textarea"; import { CreatorTester } from "../creator-tester"; -import { JsonEditorBaseModel } from "../../src/components/tabs/json-editor-plugin"; import { settings } from "../../src/creator-settings"; +import { SurveyTextWorker } from "../../src/textWorker"; test("JsonEditor & showErrors/errorList", () => { const creator = new CreatorTester(); @@ -248,3 +248,19 @@ test("Put elements into end of the JSON", () => { const titlePos = text.indexOf("title"); expect(elementsPos > titlePos).toBeTruthy(); }); +test("We should have one SurveyTextWorker.fromJSON/toJSON", () => { + const json = { requiredText: "###" }; + const creator = new CreatorTester(); + creator.activeTab ="editor"; + const editorPlugin: TabJsonEditorTextareaPlugin = creator.getPlugin("editor"); + editorPlugin.model.text = JSON.stringify(json); + let counter = 0; + SurveyTextWorker.onProcessJson = (json: any): void => { + if(json?.requiredText === "###") { + counter ++; + } + }; + creator.activeTab = "designer"; + expect(counter).toBe(1); + SurveyTextWorker.onProcessJson = undefined; +}); From 308dd10c71009551eea548e8eeda6db94e9fceb4 Mon Sep 17 00:00:00 2001 From: Andrew Telnov Date: Fri, 1 Nov 2024 21:58:46 +0200 Subject: [PATCH 2/4] Add converting from text to JSON --- packages/survey-creator-core/src/creator-base.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/survey-creator-core/src/creator-base.ts b/packages/survey-creator-core/src/creator-base.ts index 4e8f873e6d..7401845c4f 100644 --- a/packages/survey-creator-core/src/creator-base.ts +++ b/packages/survey-creator-core/src/creator-base.ts @@ -2140,7 +2140,7 @@ export class SurveyCreatorModel extends Base if (!value) { this.initSurveyWithJSON(undefined, clearState); } else { - let jsonText = trustJSON ? value : undefined; + let jsonText = trustJSON ? JSON.parse(value) : undefined; if(!trustJSON) { const textWorker = new SurveyTextWorker(value); if(textWorker.isJsonCorrect) { From aa37501d9e29455c4a0907bf8890e4b6d736f1ed Mon Sep 17 00:00:00 2001 From: Andrew Telnov Date: Sat, 2 Nov 2024 08:33:38 +0200 Subject: [PATCH 3/4] Fix unit tests --- packages/survey-creator-core/src/creator-base.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/survey-creator-core/src/creator-base.ts b/packages/survey-creator-core/src/creator-base.ts index 7401845c4f..4cd4fd2fb1 100644 --- a/packages/survey-creator-core/src/creator-base.ts +++ b/packages/survey-creator-core/src/creator-base.ts @@ -2140,24 +2140,26 @@ export class SurveyCreatorModel extends Base if (!value) { this.initSurveyWithJSON(undefined, clearState); } else { - let jsonText = trustJSON ? JSON.parse(value) : undefined; + let jsonValue = trustJSON ? this.parseJSON(value) : undefined; if(!trustJSON) { const textWorker = new SurveyTextWorker(value); if(textWorker.isJsonCorrect) { - jsonText = value; + jsonValue = this.parseJSON(value); } else if(!!textWorker.survey) { - jsonText = textWorker.survey.toJSON(); + jsonValue = textWorker.survey.toJSON(); } } - if (!!jsonText) { - this.initSurveyWithJSON(jsonText, clearState); + if (!!jsonValue) { + this.initSurveyWithJSON(jsonValue, clearState); } else { this.viewType = "editor"; } } } - + private parseJSON(val: string): any { + return new SurveyJSON5().parse(val); + } /** * A survey JSON schema as a string. * From 3f37fb40792b5e3472dda163eadc67fb79110686 Mon Sep 17 00:00:00 2001 From: Andrew Telnov Date: Mon, 4 Nov 2024 10:45:25 +0200 Subject: [PATCH 4/4] Keep old interface for plugin --- .../src/components/tabs/designer-plugin.ts | 3 ++- .../src/components/tabs/json-editor-plugin.ts | 3 ++- .../survey-creator-core/src/components/tabs/logic-plugin.ts | 3 ++- .../survey-creator-core/src/components/tabs/test-plugin.ts | 3 ++- .../survey-creator-core/src/components/tabs/theme-plugin.ts | 3 ++- .../src/components/tabs/translation-plugin.ts | 3 ++- packages/survey-creator-core/src/creator-base.ts | 4 +--- packages/survey-creator-core/src/creator-settings.ts | 2 +- packages/survey-creator-core/src/plugins/undo-redo/index.ts | 2 +- 9 files changed, 15 insertions(+), 11 deletions(-) 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 9583cd4041..140a44d35d 100644 --- a/packages/survey-creator-core/src/components/tabs/designer-plugin.ts +++ b/packages/survey-creator-core/src/components/tabs/designer-plugin.ts @@ -278,7 +278,7 @@ export class TabDesignerPlugin implements ICreatorPlugin { this.creator.focusElement(undefined, true); } - public deactivate(): void { + public deactivate(): boolean { if (this.model) { this.model.dispose(); } @@ -291,6 +291,7 @@ export class TabDesignerPlugin implements ICreatorPlugin { this.creator.sidebar.sideAreaComponentName = undefined; this.creator.sidebar.sideAreaComponentData = undefined; this.creator.sidebar.header.reset(); + return true; } public onDesignerSurveyPropertyChanged(obj: Base, propName: string): void { if (!!this.model) { diff --git a/packages/survey-creator-core/src/components/tabs/json-editor-plugin.ts b/packages/survey-creator-core/src/components/tabs/json-editor-plugin.ts index 72f33e0b0b..90893813e1 100644 --- a/packages/survey-creator-core/src/components/tabs/json-editor-plugin.ts +++ b/packages/survey-creator-core/src/components/tabs/json-editor-plugin.ts @@ -220,7 +220,7 @@ export abstract class TabJsonEditorBasePlugin implements ICreatorPlugin { public activate(): void { this.model = this.createModel(this.creator); } - public deactivate(): void { + public deactivate(): boolean { if (this.model) { if (!this.model.readOnly && this.model.isJSONChanged) { this.creator.selectedElement = undefined; @@ -231,6 +231,7 @@ export abstract class TabJsonEditorBasePlugin implements ICreatorPlugin { this.model.dispose(); this.model = undefined; } + return true; } public defaultAllowingDeactivate(): boolean { if (!this.model) return true; diff --git a/packages/survey-creator-core/src/components/tabs/logic-plugin.ts b/packages/survey-creator-core/src/components/tabs/logic-plugin.ts index e348675a40..a05636f04b 100644 --- a/packages/survey-creator-core/src/components/tabs/logic-plugin.ts +++ b/packages/survey-creator-core/src/components/tabs/logic-plugin.ts @@ -71,8 +71,9 @@ export class TabLogicPlugin implements ICreatorPlugin { } onSuccess(); } - public deactivate(): void { + public deactivate(): boolean { this.disposeObjs(); + return true; } public dispose(): void { this.disposeObjs(); diff --git a/packages/survey-creator-core/src/components/tabs/test-plugin.ts b/packages/survey-creator-core/src/components/tabs/test-plugin.ts index 92ef41b650..cf9f5153f5 100644 --- a/packages/survey-creator-core/src/components/tabs/test-plugin.ts +++ b/packages/survey-creator-core/src/components/tabs/test-plugin.ts @@ -105,7 +105,7 @@ export class TabTestPlugin implements ICreatorPlugin { } }); } - public deactivate(): void { + public deactivate(): boolean { if (this.model) { this.simulatorTheme = this.model.simulator.survey.css; this.model.onSurveyCreatedCallback = undefined; @@ -115,6 +115,7 @@ export class TabTestPlugin implements ICreatorPlugin { this.languageSelectorAction.visible = false; this.testAgainAction.visible = false; this.invisibleToggleAction && (this.invisibleToggleAction.visible = false); + return true; } private getAvailableThemes(themeMapper: Array): Array { const availableThemesToItems = []; diff --git a/packages/survey-creator-core/src/components/tabs/theme-plugin.ts b/packages/survey-creator-core/src/components/tabs/theme-plugin.ts index 37f8e08a95..537946e9e7 100644 --- a/packages/survey-creator-core/src/components/tabs/theme-plugin.ts +++ b/packages/survey-creator-core/src/components/tabs/theme-plugin.ts @@ -451,7 +451,7 @@ export class ThemeTabPlugin implements ICreatorPlugin { } }); } - public deactivate(): void { + public deactivate(): boolean { if (this.model) { this.simulatorCssClasses = this.model.survey.css; this.model.onPropertyChanged.clear(); @@ -470,6 +470,7 @@ export class ThemeTabPlugin implements ICreatorPlugin { this.propertyGridTab.visible = false; this.testAgainAction.visible = false; this.invisibleToggleAction && (this.invisibleToggleAction.visible = false); + return true; } public saveToFileHandler = saveToFileHandler; diff --git a/packages/survey-creator-core/src/components/tabs/translation-plugin.ts b/packages/survey-creator-core/src/components/tabs/translation-plugin.ts index e867beccfb..710c971186 100644 --- a/packages/survey-creator-core/src/components/tabs/translation-plugin.ts +++ b/packages/survey-creator-core/src/components/tabs/translation-plugin.ts @@ -91,7 +91,7 @@ export class TabTranslationPlugin implements ICreatorPlugin { this.model.filteredPage = null; this.updateFilterPageAction(true); } - public deactivate(): void { + public deactivate(): boolean { if (!!this.model) { this.model.dispose(); } @@ -104,6 +104,7 @@ export class TabTranslationPlugin implements ICreatorPlugin { this.mergeLocaleWithDefaultAction.visible = false; this.importCsvAction.visible = false; this.exportCsvAction.visible = false; + return true; } private createMergeLocaleWithDefaultActionTitleUpdater(): any { return new ComputedUpdater(() => { diff --git a/packages/survey-creator-core/src/creator-base.ts b/packages/survey-creator-core/src/creator-base.ts index 4cd4fd2fb1..8ce64dbf15 100644 --- a/packages/survey-creator-core/src/creator-base.ts +++ b/packages/survey-creator-core/src/creator-base.ts @@ -1197,9 +1197,7 @@ export class SurveyCreatorModel extends Base const chaningOptions = { tabName: viewName, allow: allow, model: this.currentPlugin?.model }; this.onActiveTabChanging.fire(this, chaningOptions); if (!chaningOptions.allow) return; - if(!!this.currentPlugin && this.currentPlugin.deactivate) { - this.currentPlugin.deactivate(); - } + if(!!this.currentPlugin?.deactivate && !this.currentPlugin.deactivate()) return; const plugin = this.activatePlugin(viewName); this.viewType = viewName; this.onActiveTabChanged.fire(this, { tabName: viewName, plugin: plugin, model: !!plugin ? plugin.model : undefined }); diff --git a/packages/survey-creator-core/src/creator-settings.ts b/packages/survey-creator-core/src/creator-settings.ts index 25d30d265c..7acc202686 100644 --- a/packages/survey-creator-core/src/creator-settings.ts +++ b/packages/survey-creator-core/src/creator-settings.ts @@ -189,7 +189,7 @@ export interface ICollectionItemAllowOperations { export interface ICreatorPlugin { activate: () => void; update?: () => void; - deactivate?: () => void; + deactivate?: () => boolean; canDeactivateAsync?: (onSuccess: () => void) => void; defaultAllowingDeactivate?: () => boolean | undefined; dispose?: () => void; diff --git a/packages/survey-creator-core/src/plugins/undo-redo/index.ts b/packages/survey-creator-core/src/plugins/undo-redo/index.ts index 6d7cbf8c75..ff266885c8 100644 --- a/packages/survey-creator-core/src/plugins/undo-redo/index.ts +++ b/packages/survey-creator-core/src/plugins/undo-redo/index.ts @@ -34,7 +34,7 @@ export class UndoRedoPlugin implements ICreatorPlugin { } public model: any = undefined; public activate(): void {} - public deactivate(): void {} + public deactivate(): boolean { return true; } public update(): void {} public addFooterActions() { this.model.undoAction && (this.creator.footerToolbar.actions.splice(2, 0, this.model.undoAction));