diff --git a/eclipse-scout-core/src/form/Form.ts b/eclipse-scout-core/src/form/Form.ts index a88b6660d84..b46331c7a9a 100644 --- a/eclipse-scout-core/src/form/Form.ts +++ b/eclipse-scout-core/src/form/Form.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2025 BSI Business Systems Integration AG + * Copyright (c) 2010, 2026 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -8,10 +8,10 @@ * SPDX-License-Identifier: EPL-2.0 */ import { - AbortKeyStroke, App, aria, AriaLabelledByInsertPosition, arrays, BusyIndicatorOptions, Button, ButtonSystemType, DialogLayout, DisabledStyle, DisplayParent, DisplayViewId, EnumObject, ErrorHandler, Event, EventHandler, FileChooser, - FileChooserController, FocusRule, FormController, FormEventMap, FormGrid, FormInvalidEvent, FormLayout, FormLifecycle, FormModel, FormRevealInvalidFieldEvent, GlassPaneRenderer, GroupBox, HtmlComponent, InitModelOf, KeyStroke, - KeyStrokeContext, MessageBox, MessageBoxController, MessageBoxes, NotificationBadgeStatus, ObjectOrChildModel, objects, Point, PopupWindow, PropertyChangeEvent, Rectangle, scout, Status, StatusOrModel, strings, tooltips, TreeVisitResult, - ValidationResult, webstorage, Widget, WrappedFormField + AbortKeyStroke, App, aria, AriaLabelledByInsertPosition, arrays, BusyIndicatorOptions, Button, ButtonSystemType, ChildModelOf, DialogLayout, DisabledStyle, DisplayParent, DisplayViewId, EnumObject, ErrorHandler, Event, EventHandler, + FileChooser, FileChooserController, FocusRule, FormController, FormEventMap, FormGrid, FormInvalidEvent, FormLayout, FormLifecycle, FormModel, FormRevealInvalidFieldEvent, GlassPaneRenderer, GroupBox, HtmlComponent, InitModelOf, + KeyStroke, KeyStrokeContext, MessageBox, MessageBoxController, MessageBoxes, ModelOf, NotificationBadgeStatus, ObjectOrChildModel, objects, Point, PopupWindow, PropertyChangeEvent, Rectangle, scout, Status, StatusOrModel, strings, + tooltips, TreeVisitResult, ValidationResult, webstorage, Widget, WrappedFormField } from '../index'; import $ from 'jquery'; @@ -321,13 +321,40 @@ export class Form extends Widget implements FormModel, DisplayParent { } protected _createLifecycle(): FormLifecycle { - return scout.create(FormLifecycle, { - widget: this, + // already created + if (this.lifecycle instanceof FormLifecycle) { + return this.lifecycle; + } + + const defaultModel: ModelOf = { askIfNeedSave: this.askIfNeedSave, + askIfNeedSaveText: this.askIfNeedSaveText, emptyMandatoryElementsText: this.emptyMandatoryElementsText, invalidElementsErrorText: this.invalidElementsErrorText, - invalidElementsWarningText: this.invalidElementsWarningText, - askIfNeedSaveText: this.askIfNeedSaveText + invalidElementsWarningText: this.invalidElementsWarningText + }; + + // object type + if (typeof this.lifecycle === 'string' || typeof this.lifecycle === 'function') { + return scout.create(this.lifecycle, { + ...defaultModel, + widget: this + }); + } + + // child model + if (objects.isPojo(this.lifecycle)) { + return scout.create({ + objectType: FormLifecycle, + ...defaultModel, + ...this.lifecycle as ChildModelOf, + widget: this + }) as FormLifecycle; + } + + return scout.create(FormLifecycle, { + ...defaultModel, + widget: this }); } diff --git a/eclipse-scout-core/src/form/FormModel.ts b/eclipse-scout-core/src/form/FormModel.ts index c479487d88f..1e6336807c9 100644 --- a/eclipse-scout-core/src/form/FormModel.ts +++ b/eclipse-scout-core/src/form/FormModel.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2024 BSI Business Systems Integration AG + * Copyright (c) 2010, 2026 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -7,7 +7,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -import {DisplayHint, DisplayParent, DisplayParentModel, DisplayViewId, Form, FormValidator, GroupBox, ObjectOrChildModel, StatusOrModel, Widget, WidgetModel} from '../index'; +import {ChildModelOf, DisplayHint, DisplayParent, DisplayParentModel, DisplayViewId, Form, FormLifecycle, FormValidator, GroupBox, ObjectOrChildModel, ObjectType, StatusOrModel, Widget, WidgetModel} from '../index'; export interface FormModel extends WidgetModel, DisplayParentModel { /** @@ -230,4 +230,8 @@ export interface FormModel extends WidgetModel, DisplayParentModel { * By default, the list is empty. */ validators?: FormValidator[]; + /** + * Defines the {@link FormLifecycle} for this form. + */ + lifecycle?: ObjectType | ChildModelOf; } diff --git a/eclipse-scout-core/test/form/FormSpec.ts b/eclipse-scout-core/test/form/FormSpec.ts index a74e0dea4d6..c2914a3ac52 100644 --- a/eclipse-scout-core/test/form/FormSpec.ts +++ b/eclipse-scout-core/test/form/FormSpec.ts @@ -9,8 +9,8 @@ */ import {FormSpecHelper, OutlineSpecHelper, SpecForm} from '../../src/testing/index'; import { - App, CancelMenu, CloseMenu, Dimension, fields, FileChooser, Form, FormFieldMenu, FormModel, InitModelOf, MessageBox, NotificationBadgeStatus, NullWidget, NumberField, ObjectFactory, OkMenu, Outline, Page, Popup, PopupBlockerHandler, - Rectangle, ResetMenu, SaveMenu, scout, SearchMenu, SequenceBox, Session, SplitBox, Status, StringField, strings, TabBox, TabItem, webstorage, WidgetModel, WrappedFormField + App, CancelMenu, CloseMenu, Dimension, fields, FileChooser, Form, FormFieldMenu, FormLifecycle, FormModel, InitModelOf, MessageBox, NotificationBadgeStatus, NullWidget, NumberField, ObjectFactory, OkMenu, Outline, Page, Popup, + PopupBlockerHandler, Rectangle, ResetMenu, SaveMenu, scout, SearchMenu, SequenceBox, Session, SplitBox, Status, StringField, strings, TabBox, TabItem, webstorage, WidgetModel, WrappedFormField } from '../../src/index'; import {DateField, GroupBox} from '../../src'; @@ -32,6 +32,10 @@ describe('Form', () => { helper = new FormSpecHelper(session); outlineHelper = new OutlineSpecHelper(session); uninstallUnloadHandlers(session); + session.textMap.add('FormSaveChangesQuestion', 'Do you want to save the changes?'); + session.textMap.add('FormEmptyMandatoryFieldsMessage', 'The following fields must be filled in:'); + session.textMap.add('FormInvalidFieldsMessage', 'The following fields are invalid:'); + session.textMap.add('FormInvalidFieldsWarningMessage', 'The following fields have a warning:'); }); afterEach(() => { @@ -2519,4 +2523,109 @@ describe('Form', () => { expect(numberField.value).toBe(null); }); }); + + describe('lifecycle', () => { + + it('is a FormLifecycle by default', () => { + let form = scout.create(Form, {parent: session.desktop}); + + expect(form.lifecycle).toBeInstanceOf(FormLifecycle); + expect(form.lifecycle.widget).toBe(form); + expect(form.lifecycle.askIfNeedSave).toBeTrue(); + expect(form.lifecycle.askIfNeedSaveText).toBe('Do you want to save the changes?'); + expect(form.lifecycle.emptyMandatoryElementsText).toBe('The following fields must be filled in:'); + expect(form.lifecycle.invalidElementsErrorText).toBe('The following fields are invalid:'); + expect(form.lifecycle.invalidElementsWarningText).toBe('The following fields have a warning:'); + + form = scout.create(Form, { + parent: session.desktop, + askIfNeedSave: false, + askIfNeedSaveText: 'lorem', + emptyMandatoryElementsText: 'ipsum', + invalidElementsErrorText: 'dolor', + invalidElementsWarningText: 'sit' + }); + + expect(form.lifecycle).toBeInstanceOf(FormLifecycle); + expect(form.lifecycle.widget).toBe(form); + expect(form.lifecycle.askIfNeedSave).toBeFalse(); + expect(form.lifecycle.askIfNeedSaveText).toBe('lorem'); + expect(form.lifecycle.emptyMandatoryElementsText).toBe('ipsum'); + expect(form.lifecycle.invalidElementsErrorText).toBe('dolor'); + expect(form.lifecycle.invalidElementsWarningText).toBe('sit'); + }); + + it('can be passed in model as objectType', () => { + let form = scout.create(Form, { + parent: session.desktop, + lifecycle: SpecLifecycle + }); + + expect(form.lifecycle).toBeInstanceOf(SpecLifecycle); + expect(form.lifecycle.widget).toBe(form); + expect(form.lifecycle.askIfNeedSave).toBeTrue(); + expect(form.lifecycle.askIfNeedSaveText).toBe('Do you want to save the changes?'); + expect(form.lifecycle.emptyMandatoryElementsText).toBe('The following fields must be filled in:'); + expect(form.lifecycle.invalidElementsErrorText).toBe('The following fields are invalid:'); + expect(form.lifecycle.invalidElementsWarningText).toBe('The following fields have a warning:'); + + form = scout.create(Form, { + parent: session.desktop, + lifecycle: SpecLifecycle, + askIfNeedSave: false, + askIfNeedSaveText: 'lorem', + emptyMandatoryElementsText: 'ipsum', + invalidElementsErrorText: 'dolor', + invalidElementsWarningText: 'sit' + }); + + expect(form.lifecycle).toBeInstanceOf(SpecLifecycle); + expect(form.lifecycle.widget).toBe(form); + expect(form.lifecycle.askIfNeedSave).toBeFalse(); + expect(form.lifecycle.askIfNeedSaveText).toBe('lorem'); + expect(form.lifecycle.emptyMandatoryElementsText).toBe('ipsum'); + expect(form.lifecycle.invalidElementsErrorText).toBe('dolor'); + expect(form.lifecycle.invalidElementsWarningText).toBe('sit'); + }); + + it('can be passed in model as child model', () => { + let form = scout.create(Form, { + parent: session.desktop, + lifecycle: { + objectType: SpecLifecycle + } + }); + + expect(form.lifecycle).toBeInstanceOf(SpecLifecycle); + expect(form.lifecycle.widget).toBe(form); + expect(form.lifecycle.askIfNeedSave).toBeTrue(); + expect(form.lifecycle.askIfNeedSaveText).toBe('Do you want to save the changes?'); + expect(form.lifecycle.emptyMandatoryElementsText).toBe('The following fields must be filled in:'); + expect(form.lifecycle.invalidElementsErrorText).toBe('The following fields are invalid:'); + expect(form.lifecycle.invalidElementsWarningText).toBe('The following fields have a warning:'); + + form = scout.create(Form, { + parent: session.desktop, + lifecycle: { + objectType: SpecLifecycle, + askIfNeedSave: false, + askIfNeedSaveText: 'lorem', + emptyMandatoryElementsText: 'ipsum', + invalidElementsErrorText: 'dolor', + invalidElementsWarningText: 'sit' + } + }); + + expect(form.lifecycle).toBeInstanceOf(SpecLifecycle); + expect(form.lifecycle.widget).toBe(form); + expect(form.lifecycle.askIfNeedSave).toBeFalse(); + expect(form.lifecycle.askIfNeedSaveText).toBe('lorem'); + expect(form.lifecycle.emptyMandatoryElementsText).toBe('ipsum'); + expect(form.lifecycle.invalidElementsErrorText).toBe('dolor'); + expect(form.lifecycle.invalidElementsWarningText).toBe('sit'); + }); + }); + + class SpecLifecycle extends FormLifecycle { + } });