From 38fda0f03044521fc12180ec4b1a0538e4f2737e Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 9 Jun 2024 21:14:11 +0300 Subject: [PATCH] Add survey onElementWrapperComponentName and onElementWrapperComponentData events (#8386) Co-authored-by: tsv2013 --- src/survey-events-api.ts | 13 ++++++++++ src/survey.ts | 56 +++++++++++++++++++++++----------------- tests/surveytests.ts | 56 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 99 insertions(+), 26 deletions(-) diff --git a/src/survey-events-api.ts b/src/survey-events-api.ts index c699713b6d..8c94cd5828 100644 --- a/src/survey-events-api.ts +++ b/src/survey-events-api.ts @@ -1018,4 +1018,17 @@ export interface PopupVisibleChangedEvent extends QuestionEventMixin { * Indicates whether the popup is visible now. */ visible: boolean; +} + +export interface ElementWrapperComponentEventMixin { + element: any; + wrapperName: string; + reason?: string; + item?: ItemValue; +} +export interface ElementWrapperComponentNameEvent extends ElementWrapperComponentEventMixin { + componentName: string; +} +export interface ElementWrapperComponentDataEvent extends ElementWrapperComponentEventMixin { + data: any; } \ No newline at end of file diff --git a/src/survey.ts b/src/survey.ts index a18f0f603c..765e11aa5d 100644 --- a/src/survey.ts +++ b/src/survey.ts @@ -64,7 +64,8 @@ import { MatrixCellValueChangingEvent, MatrixCellValidateEvent, DynamicPanelModifiedEvent, DynamicPanelRemovingEvent, TimerPanelInfoTextEvent, DynamicPanelItemValueChangedEvent, DynamicPanelGetTabTitleEvent, DynamicPanelCurrentIndexChangedEvent, IsAnswerCorrectEvent, DragDropAllowEvent, ScrollingElementToTopEvent, GetQuestionTitleActionsEvent, GetPanelTitleActionsEvent, GetPageTitleActionsEvent, GetPanelFooterActionsEvent, GetMatrixRowActionsEvent, ElementContentVisibilityChangedEvent, GetExpressionDisplayValueEvent, - ServerValidateQuestionsEvent, MultipleTextItemAddedEvent, MatrixColumnAddedEvent, GetQuestionDisplayValueEvent, PopupVisibleChangedEvent, ChoicesSearchEvent, OpenFileChooserEvent + ServerValidateQuestionsEvent, MultipleTextItemAddedEvent, MatrixColumnAddedEvent, GetQuestionDisplayValueEvent, PopupVisibleChangedEvent, ChoicesSearchEvent, + OpenFileChooserEvent, ElementWrapperComponentNameEvent, ElementWrapperComponentDataEvent } from "./survey-events-api"; import { QuestionMatrixDropdownModelBase } from "./question_matrixdropdownbase"; import { QuestionMatrixDynamicModel } from "./question_matrixdynamic"; @@ -843,6 +844,8 @@ export class SurveyModel extends SurveyElementCore */ public onPopupVisibleChanged: EventBase = this.addEvent(); + public onElementWrapperComponentName: EventBase = this.addEvent(); + public onElementWrapperComponentData: EventBase = this.addEvent(); //#endregion constructor(jsonObj: any = null, renderedElement: any = null) { @@ -7430,7 +7433,7 @@ export class SurveyModel extends SurveyElementCore this.focusingQuestionInfo = undefined; } - public questionEditFinishCallback(question: Question, event: any) { + public questionEditFinishCallback(question: Question, event: any): void { const enterKeyAction = this.enterKeyAction || settings.enterKeyAction; if (enterKeyAction == "loseFocus") event.target.blur(); if (enterKeyAction == "moveToNextEditor") { @@ -7444,40 +7447,45 @@ export class SurveyModel extends SurveyElementCore } } } - + private elementWrapperComponentNameCore(componentName: string, element: any, wrapperName: string, reason?: string, item?: ItemValue): string { + if(this.onElementWrapperComponentName.isEmpty) return componentName; + const options = { componentName: componentName, element: element, wrapperName: wrapperName, reason: reason, item: item }; + this.onElementWrapperComponentName.fire(this, options); + return options.componentName; + } + private elementWrapperDataCore(data: any, element: any, wrapperName: string, reason?: string, item?: ItemValue): any { + if(this.onElementWrapperComponentData.isEmpty) return data; + const options = { data: data, element: element, wrapperName: wrapperName, reason: reason, item: item }; + this.onElementWrapperComponentData.fire(this, options); + return options.data; + } public getElementWrapperComponentName(element: any, reason?: string): string { - if (reason === "logo-image") { - return "sv-logo-image"; - } - return SurveyModel.TemplateRendererComponentName; + const res = reason === "logo-image" ? "sv-logo-image" : SurveyModel.TemplateRendererComponentName; + return this.elementWrapperComponentNameCore(res, element, "component", reason); } public getQuestionContentWrapperComponentName(element: any): string { - return SurveyModel.TemplateRendererComponentName; + return this.elementWrapperComponentNameCore(SurveyModel.TemplateRendererComponentName, element, "content-component"); } public getRowWrapperComponentName(row: QuestionRowModel): string { - return SurveyModel.TemplateRendererComponentName; + return this.elementWrapperComponentNameCore(SurveyModel.TemplateRendererComponentName, row, "row"); + } + public getItemValueWrapperComponentName(item: ItemValue, question: QuestionSelectBase): string { + return this.elementWrapperComponentNameCore(SurveyModel.TemplateRendererComponentName, question, "itemvalue", undefined, item); } public getElementWrapperComponentData(element: any, reason?: string): any { - return element; + return this.elementWrapperDataCore(element, element, "component", reason); } public getRowWrapperComponentData(row: QuestionRowModel): any { - return row; + return this.elementWrapperDataCore(row, row, "row"); } - public getItemValueWrapperComponentName( - item: ItemValue, - question: QuestionSelectBase - ): string { - return SurveyModel.TemplateRendererComponentName; - } - public getItemValueWrapperComponentData( - item: ItemValue, - question: QuestionSelectBase - ): any { - return item; + public getItemValueWrapperComponentData(item: ItemValue, question: QuestionSelectBase): any { + return this.elementWrapperDataCore(item, question, "itemvalue", undefined, item); } - public getMatrixCellTemplateData(cell: any) { - return cell.question; + public getMatrixCellTemplateData(cell: any): any { + const res: any = cell.question; + return this.elementWrapperDataCore(res, res, "cell"); } + public searchText(text: string): Array { if (!!text) text = text.toLowerCase(); var res: Array = []; diff --git a/tests/surveytests.ts b/tests/surveytests.ts index eafd4462d8..673dd57ea8 100644 --- a/tests/surveytests.ts +++ b/tests/surveytests.ts @@ -2,7 +2,7 @@ import { Base } from "../src/base"; import { SurveyElement } from "../src/survey-element"; import { SurveyModel } from "../src/survey"; import { PageModel } from "../src/page"; -import { PanelModel } from "../src/panel"; +import { PanelModel, QuestionRowModel } from "../src/panel"; import { ElementFactory, QuestionFactory } from "../src/questionfactory"; import { Question } from "../src/question"; import { QuestionHtmlModel } from "../src/question_html"; @@ -14910,7 +14910,59 @@ QUnit.test("getQuestionContentWrapperComponentName", function (assert) { "default component" ); }); - +QUnit.test("onElementWrapperComponentName event", function (assert) { + const survey = new SurveyModel({ + elements: [{ type: "text", name: "q1" }, { type: "checkbox", name: "q2", choices: [1, 2] }] + }); + const q1 = survey.getQuestionByName("q1"); + const q2 = survey.getQuestionByName("q2"); + survey.onElementWrapperComponentName.add((sender, options) => { + if(options.wrapperName === "component" && options.reason === "test1") { + options.componentName += "#1"; + } + if(options.wrapperName === "content-component" && options.reason === undefined) { + options.componentName += "#2"; + } + if(options.wrapperName === "row" && !!options.element.setIsLazyRendering) { + options.componentName += "#3"; + } + if(options.wrapperName === "itemvalue" && options.item?.value === 1) { + options.componentName += "#4"; + } + }); + assert.equal(survey.getElementWrapperComponentName(q1, "test1"), "sv-template-renderer#1", "#1"); + assert.equal(survey.getQuestionContentWrapperComponentName(q1), "sv-template-renderer#2", "#2"); + assert.equal(survey.getRowWrapperComponentName(new QuestionRowModel(survey.pages[0])), "sv-template-renderer#3", "#3"); + assert.equal(survey.getItemValueWrapperComponentName(q2.choices[0], q2), "sv-template-renderer#4", "#4"); +}); +QUnit.test("onElementWrapperComponentName event", function (assert) { + const survey = new SurveyModel({ + elements: [{ type: "text", name: "q1" }, { type: "checkbox", name: "q2", choices: [1, 2] }, + { type: "matrixdynamic", name: "q3", rowCount: 1, columns: [{ name: "col1" }] } + ] + }); + const q1 = survey.getQuestionByName("q1"); + const q2 = survey.getQuestionByName("q2"); + const q3 = survey.getQuestionByName("q3"); + survey.onElementWrapperComponentData.add((sender, options) => { + if(options.wrapperName === "component" && options.reason === "test1") { + options.data = "#1"; + } + if(options.wrapperName === "row" && !!options.element.setIsLazyRendering) { + options.data = "#2"; + } + if(options.wrapperName === "itemvalue" && options.item?.value === 1) { + options.data = "#3"; + } + if(options.wrapperName === "cell" && options.element.name === "col1") { + options.data = "#4"; + } + }); + assert.equal(survey.getElementWrapperComponentData(q1, "test1"), "#1", "#1"); + assert.equal(survey.getRowWrapperComponentData(new QuestionRowModel(survey.pages[0])), "#2", "#2"); + assert.equal(survey.getItemValueWrapperComponentData(q2.choices[0], q2), "#3", "#3"); + assert.equal(survey.getMatrixCellTemplateData(q3.visibleRows[0].cells[0]), "#4", "#4"); +}); QUnit.test( "Skip trigger test and auto focus first question on the page", function (assert) {