diff --git a/packages/survey-core/src/base-interfaces.ts b/packages/survey-core/src/base-interfaces.ts index 300fc53d21..03097f470d 100644 --- a/packages/survey-core/src/base-interfaces.ts +++ b/packages/survey-core/src/base-interfaces.ts @@ -135,6 +135,7 @@ export interface ISurvey extends ITextProcessor, ISurveyErrorOwner { questionTitlePattern: string; getUpdatedQuestionTitle(question: IQuestion, title: string): string; getUpdatedQuestionNo(question: IQuestion, no: string): string; + getUpdatedPageNo(question: IPage, no: string): string; getUpdatedElementTitleActions( element: ISurveyElement, titleActions: Array diff --git a/packages/survey-core/src/page.ts b/packages/survey-core/src/page.ts index 8fae07cf2b..d009bd8c70 100644 --- a/packages/survey-core/src/page.ts +++ b/packages/survey-core/src/page.ts @@ -36,7 +36,9 @@ export class PageModel extends PanelModelBase implements IPage { return true; } public get no(): string { - return this.canShowPageNumber() ? this.num + ". " : ""; + if(!this.canShowPageNumber() || !this.survey) return ""; + let no = this.num + ". "; + return this.survey.getUpdatedPageNo(this, no); } public get cssTitleNumber(): string { return this.cssClasses.page.number; diff --git a/packages/survey-core/src/survey-events-api.ts b/packages/survey-core/src/survey-events-api.ts index b5f0f3fa11..f8b7296fa1 100644 --- a/packages/survey-core/src/survey-events-api.ts +++ b/packages/survey-core/src/survey-events-api.ts @@ -394,6 +394,11 @@ export interface GetQuestionNoEvent extends QuestionEventMixin { */ no: string; } +export interface GetQuestionNumberEvent extends GetQuestionNoEvent { +} +export interface GetPageNumberEvent extends PageEventMixin { + no: string; +} export interface ProgressTextEvent { /** * The number of questions with input fields. [Image](https://surveyjs.io/form-library/examples/add-image-and-video-to-survey/), [HTML](https://surveyjs.io/form-library/examples/questiontype-html/), and [Expression](https://surveyjs.io/form-library/examples/questiontype-expression/) questions are not counted. diff --git a/packages/survey-core/src/survey.ts b/packages/survey-core/src/survey.ts index fbc19777b4..237616f012 100644 --- a/packages/survey-core/src/survey.ts +++ b/packages/survey-core/src/survey.ts @@ -58,7 +58,7 @@ import { TriggerExecutedEvent, CompletingEvent, CompleteEvent, ShowingPreviewEvent, NavigateToUrlEvent, CurrentPageChangingEvent, CurrentPageChangedEvent, ValueChangingEvent, ValueChangedEvent, VariableChangedEvent, QuestionVisibleChangedEvent, PageVisibleChangedEvent, PanelVisibleChangedEvent, QuestionCreatedEvent, QuestionAddedEvent, QuestionRemovedEvent, PanelAddedEvent, PanelRemovedEvent, PageAddedEvent, ValidateQuestionEvent, SettingQuestionErrorsEvent, ValidatePanelEvent, - ErrorCustomTextEvent, ValidatedErrorsOnCurrentPageEvent, ProcessHtmlEvent, GetQuestionTitleEvent, GetTitleTagNameEvent, GetQuestionNoEvent, ProgressTextEvent, + ErrorCustomTextEvent, ValidatedErrorsOnCurrentPageEvent, ProcessHtmlEvent, GetQuestionTitleEvent, GetTitleTagNameEvent, GetQuestionNumberEvent, GetPageNumberEvent, ProgressTextEvent, TextMarkdownEvent, TextRenderAsEvent, SendResultEvent, GetResultEvent, UploadFilesEvent, DownloadFileEvent, ClearFilesEvent, LoadChoicesFromServerEvent, ProcessTextValueEvent, UpdateQuestionCssClassesEvent, UpdatePanelCssClassesEvent, UpdatePageCssClassesEvent, UpdateChoiceItemCssEvent, AfterRenderSurveyEvent, AfterRenderHeaderEvent, AfterRenderPageEvent, AfterRenderQuestionEvent, AfterRenderQuestionInputEvent, AfterRenderPanelEvent, FocusInQuestionEvent, FocusInPanelEvent, @@ -399,7 +399,7 @@ export class SurveyModel extends SurveyElementCore * * For information on event handler parameters, refer to descriptions within the interface. * - * If you want to modify question numbers, handle the [`onGetQuestionNo`](https://surveyjs.io/form-library/documentation/api-reference/survey-data-model#onGetQuestionNo) event. + * If you want to modify question numbers, handle the [`onGetQuestionNumber`](https://surveyjs.io/form-library/documentation/api-reference/survey-data-model#onGetQuestionNumber) event. * @see requiredText */ public onGetQuestionTitle: EventBase = this.addEvent(); @@ -412,7 +412,7 @@ export class SurveyModel extends SurveyElementCore * * [View Demo](https://surveyjs.io/form-library/examples/survey-titletagnames/ (linkStyle)) * @see onGetQuestionTitle - * @see onGetQuestionNo + * @see onGetQuestionNumber */ public onGetTitleTagName: EventBase = this.addEvent(); /** @@ -424,7 +424,9 @@ export class SurveyModel extends SurveyElementCore * @see onGetQuestionTitle * @see questionStartIndex */ - public onGetQuestionNo: EventBase = this.addEvent(); + public onGetQuestionNumber: EventBase = this.addEvent(); + public onGetQuestionNo: EventBase = this.onGetQuestionNumber; + public onGetPageNumber: EventBase = this.addEvent(); /** * An event that is raised before the survey displays progress text. Handle this event to change the progress text in code. * @see showProgressBar @@ -945,7 +947,7 @@ export class SurveyModel extends SurveyElementCore ["showPrevButton", "showCompleteButton"], () => { this.updateButtonsVisibility(); }); - this.onGetQuestionNo.onCallbacksChanged = () => { + this.onGetQuestionNumber.onCallbacksChanged = () => { this.resetVisibleIndexes(); }; this.onProgressText.onCallbacksChanged = () => { @@ -2665,9 +2667,15 @@ export class SurveyModel extends SurveyElementCore return options.title; } getUpdatedQuestionNo(question: Question, no: string): string { - if (this.onGetQuestionNo.isEmpty) return no; - const options: GetQuestionNoEvent = { question: question, no: no }; - this.onGetQuestionNo.fire(this, options); + if (this.onGetQuestionNumber.isEmpty) return no; + const options: GetQuestionNumberEvent = { question: question, no: no }; + this.onGetQuestionNumber.fire(this, options); + return options.no; + } + getUpdatedPageNo(page: PageModel, no: string): string { + if (this.onGetPageNumber.isEmpty) return no; + const options: GetPageNumberEvent = { page: page, no: no }; + this.onGetPageNumber.fire(this, options); return options.no; } /** diff --git a/packages/survey-core/tests/surveytests.ts b/packages/survey-core/tests/surveytests.ts index 2601e806f4..e4ca7a7993 100644 --- a/packages/survey-core/tests/surveytests.ts +++ b/packages/survey-core/tests/surveytests.ts @@ -3510,6 +3510,37 @@ QUnit.test("question.no and survey.questionStartIndex", function (assert) { }); assert.equal(question.no, "a.b.2)", "use event"); }); +QUnit.test("survey.onGetPageNumber event", function (assert) { + const survey = new SurveyModel(); + survey.showPageNumbers = true; + survey.onGetPageNumber.add((sender, options) => { + if(options.page.isStartPage) { + options.no = ""; + } else { + options.no = (survey.pages.indexOf(options.page) + 1) + "-"; + } + }); + survey.fromJSON({ + firstPageIsStarted: true, + pages: [ + { elements: [{ type: "text", name: "q" }] }, + { title: "Page 1", elements: [{ type: "text", name: "q1" }] }, + { title: "Page 2", elements: [{ type: "text", name: "q2" }] }, + { title: "Page 3", elements: [{ type: "text", name: "q3" }] }, + { title: "Page 4", elements: [{ type: "text", name: "q4" }] } + ] + }); + survey.start(); + assert.equal(survey.pages[0].no, "", "pages[0], #1"); + assert.equal(survey.pages[1].no, "2-", "pages[1], #1"); + assert.equal(survey.pages[2].no, "3-", "pages[2], #1"); + assert.equal(survey.pages[3].no, "4-", "pages[3], #1"); + survey.pages[1].visible = false; + assert.equal(survey.pages[0].no, "", "pages[0], #2"); + assert.equal(survey.pages[1].no, "2-", "pages[1], #2"); + assert.equal(survey.pages[2].no, "3-", "pages[2], #2"); + assert.equal(survey.pages[3].no, "4-", "pages[3], #2"); +}); QUnit.test( "question.no/queston.visibleIndex and hideNo/hideTitle options", function (assert) {