diff --git a/README.md b/README.md index d0f0f31d..751eadf6 100644 --- a/README.md +++ b/README.md @@ -19,12 +19,11 @@ Form-Actions and -fields can be customized and added by your need. # Getting started -The extension runs with CoreMedia 11 (v2201.2). And also runs with: -- v2110.1. See the release [cmcc-11-2110.1](https://github.com/tallence/core-forms/releases/tag/cmcc-11-2110.1). -- v2107.1. See the release [cmcc-10-2107.1](https://github.com/tallence/core-forms/releases/tag/cmcc-10-2107.1). +See the [releases](https://github.com/tallence/core-forms/releases) for tested compatibilities. +For earlier versions, have a look into these branches: - v2010.2. See the branch [2010.2-compatible](https://github.com/tallence/core-forms/tree/2010.2-compatible). - CoreMedia 9 (v19.04). See the branch: [1904.2-compatible](https://github.com/tallence/core-forms/tree/1904.2-compatible). - It is in general compatible with the versions 17.10 and 18.10, but some small changes could be required (import paths, names of artifacts) +- Other CoreMedia 9 versions: It is in general compatible with the versions 17.10 and 18.10, but some small changes could be required (import paths, names of artifacts) This repo covers the studio- and the backend-cae part. If you are looking for an example implementation for the frontend part (a Vue.js-App wrapped in a CoreMedia-Frontend-Workspace-Theme) have a look here: [core-forms-frontend](https://github.com/tallence/core-forms-frontend) diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/package.json b/apps/studio-client/apps/main/form-editor-studio-plugin/package.json index 02496608..fb09737a 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/package.json +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/package.json @@ -5,24 +5,24 @@ "dependencies": { "@coremedia-blueprint/studio-client.form-editor": "1.0.0-SNAPSHOT", "@coremedia-blueprint/studio-client.main.blueprint-forms": "1.0.0-SNAPSHOT", - "@coremedia/studio-client.base-models": "2201.2.0", - "@coremedia/studio-client.cap-base-models": "2201.2.0", - "@coremedia/studio-client.cap-rest-client": "2201.2.0", - "@coremedia/studio-client.client-core": "2201.2.0", - "@coremedia/studio-client.core-icons": "2201.2.0", - "@coremedia/studio-client.ext.errors-validation-components": "2201.2.0", - "@coremedia/studio-client.ext.ui-components": "2201.2.0", - "@coremedia/studio-client.main.bpbase-studio-dynamic-query-list": "2201.2.0", - "@coremedia/studio-client.main.editor-components": "2201.2.0", - "@jangaroo/ext-ts": "^1.0.2", - "@jangaroo/runtime": "^1.1.1" + "@coremedia/studio-client.base-models": "2304.1.0", + "@coremedia/studio-client.cap-base-models": "2304.1.0", + "@coremedia/studio-client.cap-rest-client": "2304.1.0", + "@coremedia/studio-client.client-core": "2304.1.0", + "@coremedia/studio-client.core-icons": "2304.1.0", + "@coremedia/studio-client.ext.errors-validation-components": "2304.1.0", + "@coremedia/studio-client.ext.ui-components": "2304.1.0", + "@coremedia/studio-client.main.bpbase-studio-dynamic-query-list": "2304.1.0", + "@coremedia/studio-client.main.editor-components": "2304.1.0", + "@jangaroo/ext-ts": "^1.0.3", + "@jangaroo/runtime": "^1.4.2" }, "devDependencies": { - "@jangaroo/build": "^1.1.1", - "@jangaroo/core": "^1.1.1", - "@jangaroo/eslint-config": "^1.1.1", - "@jangaroo/publish": "^1.1.1", - "eslint": "^7.27.0", + "@jangaroo/build": "^1.4.2", + "@jangaroo/core": "^1.4.2", + "@jangaroo/eslint-config": "^1.4.2", + "@jangaroo/publish": "^1.4.2", + "eslint": "^7.32.0", "rimraf": "^3.0.2" }, "scripts": { diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/sencha/sass/src/FormsStudioPlugin.scss b/apps/studio-client/apps/main/form-editor-studio-plugin/sencha/sass/src/FormsStudioPlugin.scss index c2d1603b..510c0cef 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/sencha/sass/src/FormsStudioPlugin.scss +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/sencha/sass/src/FormsStudioPlugin.scss @@ -4,6 +4,8 @@ $_group_container: $_block + "--element-group-container"; $_applicable_element_container: $_block + "--applicable-element-container"; + $form_page_block: "form-page-container"; + $form_element_block: "form-element-drop-container"; $form_element_drag_active: $form_element_block + "--drag-active"; $form_element_drop_active: $form_element_block + "--drop-active"; @@ -28,6 +30,14 @@ color: rgba(0, 0, 0, 0.27); } + .#{$form_page_block} { + margin: 10px 15px 0 10px; + background: transparent; + border: 2px solid rgba(0, 0, 0, 0.04); + padding: 6px; + color: rgba(0, 0, 0, 0.27); + } + .#{$form_element_drag_active} { border: 2px dashed rgba(0, 0, 0, 0.61); color: rgba(0, 0, 0, 0.61); diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/ApplicableElements.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/ApplicableElements.ts index a7c50369..df224726 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/ApplicableElements.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/ApplicableElements.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import ValueExpression from "@coremedia/studio-client.client-core/data/ValueExpression"; import Container from "@jangaroo/ext-ts/container/Container"; import Config from "@jangaroo/runtime/Config"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/ApplicableElementsHelpContainer.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/ApplicableElementsHelpContainer.ts index 15e996b7..bcf6b8a7 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/ApplicableElementsHelpContainer.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/ApplicableElementsHelpContainer.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import OpenReferenceWindowAction from "@coremedia/studio-client.main.editor-components/sdk/actions/OpenReferenceWindowAction"; import CollapsiblePanel from "@coremedia/studio-client.main.editor-components/sdk/premular/CollapsiblePanel"; import Button from "@jangaroo/ext-ts/button/Button"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/AppliedElementsContainer.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/AppliedElementsContainer.ts index 9f85e656..6fedd065 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/AppliedElementsContainer.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/AppliedElementsContainer.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import ValueExpression from "@coremedia/studio-client.client-core/data/ValueExpression"; import BindComponentsPlugin from "@coremedia/studio-client.ext.ui-components/plugins/BindComponentsPlugin"; import Container from "@jangaroo/ext-ts/container/Container"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/AppliedFormElementContainer.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/AppliedFormElementContainer.ts index 2cf834ce..6b93fb3e 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/AppliedFormElementContainer.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/AppliedFormElementContainer.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import ValueExpressionFactory from "@coremedia/studio-client.client-core/data/ValueExpressionFactory"; import IconButton from "@coremedia/studio-client.ext.ui-components/components/IconButton"; import BindPropertyPlugin from "@coremedia/studio-client.ext.ui-components/plugins/BindPropertyPlugin"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/AppliedFormElementsContainerBase.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/AppliedFormElementsContainerBase.ts index f0a0e97a..c73da844 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/AppliedFormElementsContainerBase.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/AppliedFormElementsContainerBase.ts @@ -111,7 +111,7 @@ class AppliedFormElementsContainerBase extends Container { const panel = as(this.queryById(AppliedFormElementsContainerBase.FORM_ELEMENT_PANEL), CollapsiblePanel); const formElementEditor = as(reusableComponentsService.requestComponentForReuse(this.formElement.getType()), FormElement); - if (this.formElement != formElementEditor.getFormElementStructWrapper()) { + if (formElementEditor && this.formElement != formElementEditor.getFormElementStructWrapper()) { formElementEditor.updateFormElementStructWrapper(this.formElement); const component = as(formElementEditor, Component); if (component.isInstance) { @@ -129,15 +129,10 @@ class AppliedFormElementsContainerBase extends Container { this.#panel = panel; } - override destroy(...params): void { - this.#removeReusableFormElement(); - super.destroy(params); - } - #collapsedElementChangeListener(ve: ValueExpression): void { if (ve.getValue() == this.formElement.getId()) { const formElementEditor = as(reusableComponentsService.requestComponentForReuse(this.formElement.getType()), FormElement); - if (this.formElement != formElementEditor.getFormElementStructWrapper()) { + if (formElementEditor && this.formElement != formElementEditor.getFormElementStructWrapper()) { formElementEditor.updateFormElementStructWrapper(this.formElement); const component = as(formElementEditor, Component); if (component.isInstance) { @@ -167,7 +162,7 @@ class AppliedFormElementsContainerBase extends Container { iconClassTransformer(elementType: string): string { const formElementEditor = as(reusableComponentsService.requestComponentForReuse(elementType), FormElement); - return formElementEditor.getFormElementIconCls() || ""; + return formElementEditor ? formElementEditor.getFormElementIconCls() : ""; } static getTitleUndefinedValue(formElement: FormElementStructWrapper): string { @@ -181,11 +176,22 @@ class AppliedFormElementsContainerBase extends Container { /** * Before the applied form elements container is destroyed, the reusable form element must be removed from the - * container. This means that the component can still be reused and is not destroyed itself. + * container. This means that the component can still be reused and is not destroyed itself. It is checked whether a + * reusable component can be found for the given form element. This is not possible for a page as form element, + * because the container is not reusable as switching between pageable and a single page form is possible. */ #removeReusableFormElement(): void { this.formElementsManager.getCollapsedElementVE().removeChangeListener(bind(this, this.#collapsedElementChangeListener)); - reusableComponentsService.removeReusableComponentCleanly(reusableComponentsService.requestComponentForReuse(this.formElement.getType())); + let requestComponentForReuse = reusableComponentsService.requestComponentForReuse(this.formElement.getType()); + if (requestComponentForReuse) { + reusableComponentsService.removeReusableComponentCleanly(requestComponentForReuse); + } + } + + + override destroy(...args): any { + this.#removeReusableFormElement(); + return super.destroy(...args); } } diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/AppliedFormPageContainer.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/AppliedFormPageContainer.ts new file mode 100644 index 00000000..ac1993e7 --- /dev/null +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/AppliedFormPageContainer.ts @@ -0,0 +1,50 @@ +import ValueExpressionFactory from "@coremedia/studio-client.client-core/data/ValueExpressionFactory"; +import Config from "@jangaroo/runtime/Config"; +import ConfigUtils from "@jangaroo/runtime/ConfigUtils"; +import StateFulCollapsiblePanel from "./components/StateFulCollapsiblePanel"; +import ShowFormIssuesPlugin from "./plugins/ShowFormIssuesPlugin"; +import AppliedFormPageContainerBase from "./AppliedFormPageContainerBase"; +import PageElementEditor from "./elements/PageElementEditor"; +import FormEditor_properties from "./bundles/FormEditor_properties"; + +interface AppliedFormPageContainerConfig extends Config { +} + +class AppliedFormPageContainer extends AppliedFormPageContainerBase { + declare Config: AppliedFormPageContainerConfig; + + static override readonly xtype: string = "com.tallence.formeditor.studio.config.appliedFormPageContainer"; + + constructor(config: Config = null) { + super((() => ConfigUtils.apply(Config(AppliedFormPageContainer, { + + items: [ + /* We need to overwrite the collapsedCls. Otherwise the header would have a transparent background. */ + Config(StateFulCollapsiblePanel, { + margin: "10 15 0 10", + collapsible: false, + itemId: AppliedFormPageContainerBase.FORM_ELEMENT_PANEL, + collapsedCls: "collapsed-form-element", + animCollapse: false, + title: FormEditor_properties.FormEditor_pages_properties_title, + plugins: [ + Config(ShowFormIssuesPlugin, { + issuesVE: config.bindTo.extendBy(["issues"]), + propertyPathVE: ValueExpressionFactory.createFromValue(config.formElement.getPropertyPath()), + }), + ], + items: [ + Config(PageElementEditor, { + itemId: AppliedFormPageContainerBase.FORM_PAGE_EDITOR, + bindTo: config.bindTo, + forceReadOnlyValueExpression: config.forceReadOnlyValueExpression, + formElement: config.formElement + }) + ], + }) + ], + }), config))()); + } +} + +export default AppliedFormPageContainer; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/AppliedFormPageContainerBase.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/AppliedFormPageContainerBase.ts new file mode 100644 index 00000000..78c39179 --- /dev/null +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/AppliedFormPageContainerBase.ts @@ -0,0 +1,82 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import ValueExpression from "@coremedia/studio-client.client-core/data/ValueExpression"; +import PropertyEditorUtil from "@coremedia/studio-client.main.editor-components/sdk/util/PropertyEditorUtil"; +import Container from "@jangaroo/ext-ts/container/Container"; +import Config from "@jangaroo/runtime/Config"; +import FormElementsManager from "./helper/FormElementsManager"; +import FormElementStructWrapper from "./model/FormElementStructWrapper"; +import PageElementEditor from "./elements/PageElementEditor"; +import createComponentSelector from "@coremedia/studio-client.ext.ui-components/util/createComponentSelector"; + +interface AppliedFormPageContainerBaseConfig extends Config, Partial> { +} + +class AppliedFormPageContainerBase extends Container { + declare Config: AppliedFormPageContainerBaseConfig; + + protected static readonly FORM_ELEMENT_PANEL: string = "form-element-collapsible-panel"; + protected static readonly FORM_ELEMENT_HEADER: string = "form-element-header"; + protected static readonly FORM_PAGE_EDITOR: string = "pageEditor"; + + #bindTo: ValueExpression = null; + #forceReadOnlyValueExpression: ValueExpression = null; + #formElement: FormElementStructWrapper = null; + #formElementsManager: FormElementsManager = null; + #readOnlyVE: ValueExpression = null; + + set bindTo(value: ValueExpression) { + this.#bindTo = value; + } + + set forceReadOnlyValueExpression(value: ValueExpression) { + this.#forceReadOnlyValueExpression = value; + } + + set formElement(value: FormElementStructWrapper) { + this.#formElement = value; + } + + set formElementsManager(value: FormElementsManager) { + this.#formElementsManager = value; + } + + constructor(config: Config = null) { + super(config); + this.formElement = config.formElement; + this.formElementsManager = config.formElementsManager; + // Create a value expression to bind the disabled state of the drag source. It is necessary to use the two + // value expressions 'bindTo' and 'forceReadOnlyValueExpression' to create the read only value expression. If a + // content is checked out by another user, the read only value is not stored in the forceReadOnlyValueExpression. + this.#readOnlyVE = PropertyEditorUtil.createReadOnlyValueExpression(config.bindTo, config.forceReadOnlyValueExpression); + } + + protected override afterRender(): void { + super.afterRender(); + const formElementEditor = this.query(createComponentSelector().itemId(AppliedFormPageContainerBase.FORM_PAGE_EDITOR).build())[0] as PageElementEditor; + if (this.formElement != formElementEditor.getFormElementStructWrapper()) { + formElementEditor.updateFormElementStructWrapper(this.formElement); + } + } + +} + +export default AppliedFormPageContainerBase; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/FormEditorDocumentForm.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/FormEditorDocumentForm.ts index 480d0ea9..01c53e3d 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/FormEditorDocumentForm.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/FormEditorDocumentForm.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import PropertyEditorUtil from "@coremedia/studio-client.main.editor-components/sdk/util/PropertyEditorUtil"; import Ext from "@jangaroo/ext-ts"; import Container from "@jangaroo/ext-ts/container/Container"; @@ -6,14 +22,18 @@ import Config from "@jangaroo/runtime/Config"; import ConfigUtils from "@jangaroo/runtime/ConfigUtils"; import ApplicableElements from "./ApplicableElements"; import ApplicableElementsHelpContainer from "./ApplicableElementsHelpContainer"; -import AppliedElementsContainer from "./AppliedElementsContainer"; import FormEditorDocumentFormBase from "./FormEditorDocumentFormBase"; import FormEditor_properties from "./bundles/FormEditor_properties"; +import AppliedElementsContainer from "./AppliedElementsContainer"; +import SwitchingContainer from "@coremedia/studio-client.ext.ui-components/components/SwitchingContainer"; +import ValueExpressionFactory from "@coremedia/studio-client.client-core/data/ValueExpressionFactory"; +import PagesWrapperContainer from "./pages/PagesWrapperContainer"; +import ContentPropertyNames from "@coremedia/studio-client.cap-rest-client/content/ContentPropertyNames"; +import FormsStudioPlugin from "./FormsStudioPlugin"; interface FormEditorDocumentFormConfig extends Config, Partial> { + "formElements" | + "structPropertyName">> { } class FormEditorDocumentForm extends FormEditorDocumentFormBase { @@ -21,6 +41,9 @@ class FormEditorDocumentForm extends FormEditorDocumentFormBase { static override readonly xtype: string = "com.tallence.formeditor.studio.config.formEditor"; + static readonly APPLIED_FORM_ELEMENTS: string = "appliedFormElements"; + static readonly APPLIED_FORM_PAGES: string = "appliedFormPages"; + #formElements: Array = null; /* @@ -52,8 +75,12 @@ class FormEditorDocumentForm extends FormEditorDocumentFormBase { this.initReusableComponents(config.formElements); } + getActiveAppliedContainer(pageableFeatureEnabled: Boolean): string { + return pageableFeatureEnabled ? FormEditorDocumentForm.APPLIED_FORM_PAGES : FormEditorDocumentForm.APPLIED_FORM_ELEMENTS; + } + constructor(config: Config = null) { - super((()=>{ + super((() => { this.#__initialize__(config); return ConfigUtils.apply(Config(FormEditorDocumentForm, { title: FormEditor_properties.FormEditor_tab_formFields_title, @@ -75,7 +102,7 @@ class FormEditorDocumentForm extends FormEditorDocumentFormBase { dragActiveVE: this.getFormElementsManager(config.bindTo, config.forceReadOnlyValueExpression, config.structPropertyName).getDragActiveVE(), readOnlyVE: PropertyEditorUtil.createReadOnlyValueExpression(config.bindTo, config.forceReadOnlyValueExpression), }), - Config(ApplicableElementsHelpContainer, { helpTextUrl: ConfigUtils.asString(Ext.manifest.globalResources[FormEditor_properties.FormEditor_window_html_content_key]) }), + Config(ApplicableElementsHelpContainer, {helpTextUrl: ConfigUtils.asString(Ext.manifest.globalResources[FormEditor_properties.FormEditor_window_html_content_key])}), ], }), /* right column, applied form elements */ @@ -84,18 +111,31 @@ class FormEditorDocumentForm extends FormEditorDocumentFormBase { layout: "anchor", autoScroll: true, items: [ - /* applied form Elements */ - Config(AppliedElementsContainer, { - bindTo: config.bindTo, - forceReadOnlyValueExpression: config.forceReadOnlyValueExpression, - formElementsManager: this.getFormElementsManager(config.bindTo, config.forceReadOnlyValueExpression, config.structPropertyName), + Config(SwitchingContainer, { + activeItemValueExpression: ValueExpressionFactory.createTransformingValueExpression(config.bindTo.extendBy(ContentPropertyNames.PROPERTIES, FormsStudioPlugin.PAGEABLE_ENABLED), this.getActiveAppliedContainer), + items: [ + /* applied form pages */ + Config(AppliedElementsContainer, { + bindTo: config.bindTo, + itemId: FormEditorDocumentForm.APPLIED_FORM_ELEMENTS, + forceReadOnlyValueExpression: config.forceReadOnlyValueExpression, + formElementsManager: this.getFormElementsManager(config.bindTo, config.forceReadOnlyValueExpression, config.structPropertyName), + }), + /* applied form elements */ + Config(PagesWrapperContainer, { + itemId: FormEditorDocumentForm.APPLIED_FORM_PAGES, + bindTo: config.bindTo, + forceReadOnlyValueExpression: config.forceReadOnlyValueExpression, + formElementsManager: this.getFormElementsManager(config.bindTo, config.forceReadOnlyValueExpression, config.structPropertyName), + }) + ], }), ], }), /* end right column */ ], /*Hbox layout for the main content beneath the header */ - layout: Config(HBoxLayout, { align: "stretch" }), + layout: Config(HBoxLayout, {align: "stretch"}), }), ], diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/FormUtils.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/FormUtils.ts index d6080a66..47e1f657 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/FormUtils.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/FormUtils.ts @@ -19,6 +19,15 @@ import PreviewPanel from "@coremedia/studio-client.main.editor-components/sdk/pr import Panel from "@jangaroo/ext-ts/panel/Panel"; import { as, cast } from "@jangaroo/runtime"; import FormEditor_properties from "./bundles/FormEditor_properties"; +import Format from "@jangaroo/ext-ts/util/Format"; +import Content from "@coremedia/studio-client.cap-rest-client/content/Content"; +import ValueExpression from "@coremedia/studio-client.client-core/data/ValueExpression"; +import Struct from "@coremedia/studio-client.cap-rest-client/struct/Struct"; +import FormsStudioPlugin from "./FormsStudioPlugin"; +import FormElementStructWrapper from "./model/FormElementStructWrapper"; +import PageElementEditor from "./elements/PageElementEditor"; +import FormsStudioPluginBase from "./FormsStudioPluginBase"; +import ContentPropertyNames from "@coremedia/studio-client.cap-rest-client/content/ContentPropertyNames"; class FormUtils { @@ -43,6 +52,80 @@ class FormUtils { return FormEditor_properties["FormEditor_label_element_" + keyToUse] || key; } + /** + * Resolves the matching delete button tooltip based on the given disabled state. + */ + public static getOptionRemoveButtonToolTip(disabled:Boolean):String { + return disabled ? FormEditor_properties['FormEditor_text_add_option_disabled'] + : FormEditor_properties['FormEditor_text_add_option']; + } + + /** + * Validates the option, it must not be empty and must not contain dots. + * Regarding the dots:
+ * the option name is currently used as the struct-property key and it can't be used for Property ValueExpressions if + * it contain dots. A better solution would be: + *
    + *
  1. escaping the dots, or if it does not work
  2. + *
  3. save all new options in a new structure (the displayName is not used as the key of the structProperty) but stay compatible with the old structure to avoid a content-migration
  4. + *
      + */ + public static validateOptionValue(option:string):Boolean { + return option != null && Format.trim(option).length && option.indexOf(".") == -1; + } + + /** + * Deactivate the multi-page mode and flatten the formElements of all pages into a single list. + * @param content the current content + * @param self the current contents value Expression + */ + static migrateToSinglePageForm(content: Content, self: ValueExpression) { + const formData: Struct = content.getProperties().get(FormsStudioPlugin.FORM_ELEMENTS_STRUCT_PROPERTY); + if (formData.getType().getPropertyNames() && formData.getType().getPropertyNames().indexOf(FormElementStructWrapper.FORM_ELEMENTS_PROPERTY) != -1) { + + const formElements: Struct = formData.get(FormElementStructWrapper.FORM_ELEMENTS_PROPERTY); + const flattenedFormElements: Record = {}; + for (const propertyName of formElements.getType().getPropertyNames()) { + let formElement: Struct = formElements.get(propertyName); + if (formElement.get(FormElementStructWrapper.TYPE_PROPERTY) == PageElementEditor.FIELD_TYPE) { + FormUtils.buildFormElementsRecord(formElement.get(FormElementStructWrapper.FORM_ELEMENTS_PROPERTY), flattenedFormElements); + } + } + FormsStudioPluginBase.initInitialElements(content, flattenedFormElements); + + } else { + FormsStudioPluginBase.initInitialElements(content); + } + self.extendBy(ContentPropertyNames.PROPERTIES, FormsStudioPlugin.PAGEABLE_ENABLED).setValue(0); + } + + /** + * Activate the multi-page mode, create one page and move all formElements into it. + * @param content the current content + * @param self the current contents value Expression + */ + static migrateToMultiPageForm(content: Content, self: ValueExpression) { + const formData: Struct = content.getProperties().get(FormsStudioPlugin.FORM_ELEMENTS_STRUCT_PROPERTY); + if (formData.getType().getPropertyNames() && formData.getType().getPropertyNames().indexOf(FormElementStructWrapper.FORM_ELEMENTS_PROPERTY) != -1) { + + const formElements: Struct = formData.get(FormElementStructWrapper.FORM_ELEMENTS_PROPERTY); + const newElements: Record = {}; + FormUtils.buildFormElementsRecord(formElements, newElements); + FormsStudioPluginBase.initInitialPage(content, newElements); + } else { + FormsStudioPluginBase.initInitialPage(content); + } + self.extendBy(ContentPropertyNames.PROPERTIES, FormsStudioPlugin.PAGEABLE_ENABLED).setValue(1); + } + + private static buildFormElementsRecord(formElements: Struct, newElements: Record): void { + for (const [key, value] of Object.entries(formElements.toObject())) { + if (newElements[key] == undefined && !Array.isArray(value)) { + newElements[key] = value; + } + } + } + } export default FormUtils; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/FormsStudioPlugin.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/FormsStudioPlugin.ts index a1caa1f0..333b5aed 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/FormsStudioPlugin.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/FormsStudioPlugin.ts @@ -1,9 +1,31 @@ -import Validators_properties from "@coremedia/studio-client.ext.errors-validation-components/validation/Validators_properties"; -import com_coremedia_blueprint_base_queryeditor_QueryEditor_properties from "@coremedia/studio-client.main.bpbase-studio-dynamic-query-list/QueryEditor_properties"; -import CopyResourceBundleProperties from "@coremedia/studio-client.main.editor-components/configuration/CopyResourceBundleProperties"; -import AddTabbedDocumentFormsPlugin from "@coremedia/studio-client.main.editor-components/sdk/plugins/AddTabbedDocumentFormsPlugin"; -import TabbedDocumentFormDispatcher from "@coremedia/studio-client.main.editor-components/sdk/premular/TabbedDocumentFormDispatcher"; +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Validators_properties + from "@coremedia/studio-client.ext.errors-validation-components/validation/Validators_properties"; +import com_coremedia_blueprint_base_queryeditor_QueryEditor_properties + from "@coremedia/studio-client.main.bpbase-studio-dynamic-query-list/QueryEditor_properties"; +import CopyResourceBundleProperties + from "@coremedia/studio-client.main.editor-components/configuration/CopyResourceBundleProperties"; +import AddTabbedDocumentFormsPlugin + from "@coremedia/studio-client.main.editor-components/sdk/plugins/AddTabbedDocumentFormsPlugin"; +import TabbedDocumentFormDispatcher + from "@coremedia/studio-client.main.editor-components/sdk/premular/TabbedDocumentFormDispatcher"; import Config from "@jangaroo/runtime/Config"; + import ConfigUtils from "@jangaroo/runtime/ConfigUtils"; import resourceManager from "@jangaroo/runtime/l10n/resourceManager"; import FormsStudioPluginBase from "./FormsStudioPluginBase"; @@ -17,6 +39,9 @@ interface FormsStudioPluginConfig extends Config { class FormsStudioPlugin extends FormsStudioPluginBase { declare Config: FormsStudioPluginConfig; + static readonly FORM_EDITOR_DOCTYPE: string = "FormEditor"; + static readonly FORM_ELEMENTS_STRUCT_PROPERTY: string = "formData"; + static readonly PAGEABLE_ENABLED: string = "pageableFormEnabled"; static readonly xtype: string = "com.tallence.formeditor.studio.config.formsStudioPlugin"; constructor(config: Config = null) { @@ -28,7 +53,7 @@ class FormsStudioPlugin extends FormsStudioPluginBase { plugins: [ Config(AddTabbedDocumentFormsPlugin, { documentTabPanels: [ - Config(FormEditorForm, { itemId: "FormEditor" }), + Config(FormEditorForm, {itemId: FormsStudioPlugin.FORM_EDITOR_DOCTYPE}), ], }), ], diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/FormsStudioPluginBase.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/FormsStudioPluginBase.ts index cd7ea87e..2a80e5f0 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/FormsStudioPluginBase.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/FormsStudioPluginBase.ts @@ -18,6 +18,13 @@ import StudioPlugin from "@coremedia/studio-client.main.editor-components/config import IEditorContext from "@coremedia/studio-client.main.editor-components/sdk/IEditorContext"; import Config from "@jangaroo/runtime/Config"; import FormsStudioPlugin from "./FormsStudioPlugin"; +import editorContext from "@coremedia/studio-client.main.editor-components/sdk/editorContext"; +import Content from "@coremedia/studio-client.cap-rest-client/content/Content"; +import Struct from "@coremedia/studio-client.cap-rest-client/struct/Struct"; +import ContentInitializer from "@coremedia-blueprint/studio-client.main.blueprint-forms/util/ContentInitializer"; +import FormElementsManager from "./helper/FormElementsManager"; +import FormEditor_properties from "./bundles/FormEditor_properties"; +import FormElementStructWrapper from "./model/FormElementStructWrapper"; interface FormsStudioPluginBaseConfig extends Config { } @@ -31,7 +38,40 @@ class FormsStudioPluginBase extends StudioPlugin { override init(editorContext: IEditorContext): void { super.init(editorContext); + FormsStudioPluginBase.applyInitializers(); + } + + static applyInitializers(): void { + editorContext._.registerContentInitializer(FormsStudioPlugin.FORM_EDITOR_DOCTYPE, FormsStudioPluginBase.#initForm); + } + + static #initForm(content: Content): void { + ContentInitializer.initCMLinkable(content); + + ContentInitializer.setProperty(content, FormsStudioPlugin.PAGEABLE_ENABLED, 1); + FormsStudioPluginBase.initInitialPage(content); + } + + static initInitialPage(content: Content, newElements: Record = null): void { + FormsStudioPluginBase.initInitialElements(content); + const formData: Struct = content.getProperties().get(FormsStudioPlugin.FORM_ELEMENTS_STRUCT_PROPERTY); + const formElements: Struct = formData.get(FormElementStructWrapper.FORM_ELEMENTS_PROPERTY); + formElements.getType().addStructProperty( + FormElementsManager.generateRandomId().toString(), + FormElementsManager.getPageInitialData(FormEditor_properties.FormEditor_pages_default_title, newElements)); + + } + static initInitialElements(content: Content, initialElements: Record = null): void { + const formData: Struct = content.getProperties().get(FormsStudioPlugin.FORM_ELEMENTS_STRUCT_PROPERTY); + if (formData.getType().getPropertyNames() && formData.getType().getPropertyNames().indexOf(FormElementStructWrapper.FORM_ELEMENTS_PROPERTY) != -1) { + formData.getType().removeProperty(FormElementStructWrapper.FORM_ELEMENTS_PROPERTY); + } + if (initialElements) { + formData.getType().addStructProperty(FormElementStructWrapper.FORM_ELEMENTS_PROPERTY, initialElements); + } else { + formData.getType().addStructProperty(FormElementStructWrapper.FORM_ELEMENTS_PROPERTY); + } } } diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/bundles/FormContentTypes_de_properties.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/bundles/FormContentTypes_de_properties.ts index 1db213c8..92adb80f 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/bundles/FormContentTypes_de_properties.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/bundles/FormContentTypes_de_properties.ts @@ -15,6 +15,7 @@ ResourceBundleUtil.override(FormContentTypes_properties, { FormEditor_spamProtectionEnabled_text: "Spam-Schutz aktivieren", FormEditor_spamProtectionEnabled_true_text: "Spam-Schutz aktivieren", FormEditor_spamProtectionEnabled_group_text: "Spam-Schutz", + FormEditor_pageableFormEnabled_group_text: "Mehrseitigkeit", "FormEditor_formData.formElements.{formElementId:[0-9]+}.name_text": "Name", "FormEditor_formData.formElements.{formElementId:[0-9]+}.hint_text": "Hinweis", "FormEditor_formData.formElements.{formElementId:[0-9]+}.linkTarget_text": "Einverständniserklärung", diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/bundles/FormContentTypes_properties.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/bundles/FormContentTypes_properties.ts index 5b9a3eff..89421f6c 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/bundles/FormContentTypes_properties.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/bundles/FormContentTypes_properties.ts @@ -17,6 +17,7 @@ interface FormContentTypes_properties { FormEditor_spamProtectionEnabled_text: string; FormEditor_spamProtectionEnabled_true_text: string; FormEditor_spamProtectionEnabled_group_text: string; + FormEditor_pageableFormEnabled_group_text: string; "FormEditor_formData.formElements.{formElementId:[0-9]+}.name_text": string; "FormEditor_formData.formElements.{formElementId:[0-9]+}.hint_text": string; "FormEditor_formData.formElements.{formElementId:[0-9]+}.linkTarget_text": string; @@ -39,6 +40,7 @@ const FormContentTypes_properties: FormContentTypes_properties = { FormEditor_spamProtectionEnabled_text: "activate spam protection", FormEditor_spamProtectionEnabled_true_text: "activate spam protection", FormEditor_spamProtectionEnabled_group_text: "Spam protection", + FormEditor_pageableFormEnabled_group_text: "Pageable form", "FormEditor_formData.formElements.{formElementId:[0-9]+}.name_text": "Name", "FormEditor_formData.formElements.{formElementId:[0-9]+}.hint_text": "Hint", "FormEditor_formData.formElements.{formElementId:[0-9]+}.linkTarget_text": "Consent Form", diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/bundles/FormEditor_de_properties.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/bundles/FormEditor_de_properties.ts index 1b537ff3..c7063112 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/bundles/FormEditor_de_properties.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/bundles/FormEditor_de_properties.ts @@ -25,6 +25,7 @@ ResourceBundleUtil.override(FormEditor_properties, { FormEditor_label_element_phoneField: "Telefon", FormEditor_label_element_streetNumberField: "Straße & Haus-Nr.", FormEditor_label_element_zipField: "Postleitzahl", + FormEditor_label_element_ibanField: "IBAN-Feld", FormEditor_label_query_title: "Gewählte Formularelemente", FormEditor_tooltip_deletethis: "Dieses Formularelement löschen", FormEditor_label_delete_all_elements: "Alle Elemente löschen", @@ -33,6 +34,7 @@ ResourceBundleUtil.override(FormEditor_properties, { FormEditor_text_add_element: "Ziehen Sie ein Formularelement hierher.", FormEditor_text_label_option: "Optionen", FormEditor_text_add_option: "Neue Option hinzufügen", + FormEditor_text_add_option_disabled: "Der Optionstext darf nicht leer sein und keine Punkte enthalten.", FormEditor_text_edit_option: "Option bearbeiten", FormEditor_text_save_option: "Option löschen", FormEditor_text_move_option_up: "Option nach oben", @@ -59,6 +61,8 @@ ResourceBundleUtil.override(FormEditor_properties, { FormEditor_element_collapsiblePanel_label: "Einklappbares Formularelement.", FormEditor_element_textField_emptyText: "Bitte einen Text eingeben.", FormEditor_element_numberField_emptyText: "Bitte eine Nummer eingeben.", + FormEditor_element_hiddenField_value_label: "Versteckter Wert", + FormEditor_element_hiddenField_value_emptyText: "Bitte den versteckten Wert eingeben.", FormEditor_element_name_label: "Name", FormEditor_element_name_emptyText: "Der Name des Feldes.", FormEditor_element_hint_label: "Hinweis", @@ -106,4 +110,23 @@ ResourceBundleUtil.override(FormEditor_properties, { FormEditor_advancedSettings_tabs_layout_columnWidth_emptyText: "Hier eine Spaltenbreite für das Formularfeld eingeben.", FormEditor_advancedSettings_tabs_layout_breakAfter_fieldLabel: "Zeilenumbruch nach diesem Element.", FormEditor_advancedSettings_tabs_layout_description: "Mit dieser Einstellung kann eine eigene Spaltenbreite für das Feld vergeben werden.", + FormEditor_pages_mode_single: "Mehrseiten-Modus deaktivieren", + FormEditor_pages_mode_multi: "Mehrseiten-Modus aktivieren", + FormEditor_pages_mode_switch_title: "Seitenmodus", + FormEditor_pages_mode_switch_text_multi: "Den Mehrseiten-Modus aktivieren und alle Elemente in die erste Seite verschieben.", + FormEditor_pages_mode_switch_text_single: "Den Einseiten-Modus aktivieren und alle Elemente in diese Seite verschieben.", + FormEditor_pages_default_title: "Default", + FormEditor_pages_new_title: "Neue Seite", + FormEditor_pages_properties_title: "Seiten Eigenschaften", + FormEditor_page_type_field_label: "Seiten Typ", + FormEditor_page_type_empty_text: "Seitentyp auswählen", + FormEditor_page_type_default_label: "Default", + FormEditor_page_type_summary_label: "Zusammenfassung", + FormEditor_page_title_field_label: "Seiten Titel", + FormEditor_page_title_empty_text: "Seitentitel eingeben", + FormEditor_page_tab_moveUp_text: "Die Seite nach links verschieben", + FormEditor_page_tab_moveDown_text: "Die Seite nach rechts verschieben", + FormEditor_page_tab_delete_text: "Die Seite löschen", + FormEditor_page_tab_insertBefore_text: "Links eine neue Seite einfügen", + FormEditor_page_tab_insertAfter_text: "Rechts eine neue Seite einfügen", }); diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/bundles/FormEditor_properties.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/bundles/FormEditor_properties.ts index 49fa8a25..b8fee58b 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/bundles/FormEditor_properties.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/bundles/FormEditor_properties.ts @@ -24,6 +24,7 @@ interface FormEditor_properties { FormEditor_label_element_phoneField: string; FormEditor_label_element_streetNumberField: string; FormEditor_label_element_zipField: string; + FormEditor_label_element_ibanField: string; FormEditor_label_query_title: string; FormEditor_tooltip_deletethis: string; FormEditor_label_delete_all_elements: string; @@ -32,6 +33,7 @@ interface FormEditor_properties { FormEditor_text_add_element: string; FormEditor_text_label_option: string; FormEditor_text_add_option: string; + FormEditor_text_add_option_disabled: string; FormEditor_text_edit_option: string; FormEditor_text_save_option: string; FormEditor_text_move_option_up: string; @@ -59,6 +61,8 @@ interface FormEditor_properties { FormEditor_element_collapsiblePanel_label: string; FormEditor_element_textField_emptyText: string; FormEditor_element_numberField_emptyText: string; + FormEditor_element_hiddenField_value_label: string; + FormEditor_element_hiddenField_value_emptyText: string; FormEditor_element_dateField_autoToday: string; FormEditor_element_name_label: string; FormEditor_element_name_emptyText: string; @@ -109,6 +113,25 @@ interface FormEditor_properties { FormEditor_advancedSettings_tabs_layout_columnWidth_emptyText: string; FormEditor_advancedSettings_tabs_layout_breakAfter_fieldLabel: string; FormEditor_advancedSettings_tabs_layout_description: string; + FormEditor_pages_mode_single: string, + FormEditor_pages_mode_multi: string, + FormEditor_pages_mode_switch_title: string, + FormEditor_pages_mode_switch_text_multi: string, + FormEditor_pages_mode_switch_text_single: string, + FormEditor_pages_default_title: string; + FormEditor_pages_new_title: string; + FormEditor_pages_properties_title: string; + FormEditor_page_type_field_label: string; + FormEditor_page_type_empty_text: string; + FormEditor_page_type_default_label: string; + FormEditor_page_type_summary_label: string; + FormEditor_page_title_field_label: string; + FormEditor_page_title_empty_text: string; + FormEditor_page_tab_moveUp_text: string; + FormEditor_page_tab_moveDown_text: string; + FormEditor_page_tab_delete_text: string; + FormEditor_page_tab_insertBefore_text: string; + FormEditor_page_tab_insertAfter_text: string; } /** @@ -135,6 +158,7 @@ const FormEditor_properties: FormEditor_properties = { FormEditor_label_element_phoneField: "Phone", FormEditor_label_element_streetNumberField: "Street & HouseNr.", FormEditor_label_element_zipField: "Zip", + FormEditor_label_element_ibanField: "IBAN field", FormEditor_label_query_title: "Selected form elements", FormEditor_tooltip_deletethis: "Delete this element", FormEditor_label_delete_all_elements: "Delete all elements", @@ -143,6 +167,7 @@ const FormEditor_properties: FormEditor_properties = { FormEditor_text_add_element: "Drop a form element here.", FormEditor_text_label_option: "Options", FormEditor_text_add_option: "Add new option", + FormEditor_text_add_option_disabled: "The option text must not be empty or contain dots", FormEditor_text_edit_option: "Edit option", FormEditor_text_save_option: "Save option", FormEditor_text_move_option_up: "Move option up", @@ -170,6 +195,8 @@ const FormEditor_properties: FormEditor_properties = { FormEditor_element_collapsiblePanel_label: "Collapsible form element.", FormEditor_element_textField_emptyText: "Please enter a text.", FormEditor_element_numberField_emptyText: "Please enter a number.", + FormEditor_element_hiddenField_value_label: "Hidden value", + FormEditor_element_hiddenField_value_emptyText: "Please enter the hidden value.", FormEditor_element_dateField_autoToday: "Always set to current date", FormEditor_element_name_label: "Name", FormEditor_element_name_emptyText: "Name of the form field.", @@ -220,6 +247,25 @@ const FormEditor_properties: FormEditor_properties = { FormEditor_advancedSettings_tabs_layout_columnWidth_emptyText: "Please enter a custom column width.", FormEditor_advancedSettings_tabs_layout_breakAfter_fieldLabel: "Break after this element.", FormEditor_advancedSettings_tabs_layout_description: "This setting can be used to modify the layout of the form element.", + FormEditor_pages_mode_single: "Switch to the single page mode", + FormEditor_pages_mode_multi: "Switch to the multi page mode", + FormEditor_pages_mode_switch_title: "Page mode", + FormEditor_pages_mode_switch_text_multi: "Activate the Multi-Page-Mode and move the current form fields into the first page.", + FormEditor_pages_mode_switch_text_single: "Activate the Single-Page-Mode and move all form fields into the single page.", + FormEditor_pages_default_title: "Default", + FormEditor_pages_new_title: "New Page", + FormEditor_pages_properties_title: "Page properties", + FormEditor_page_type_field_label: "Page typ", + FormEditor_page_type_empty_text: "Select page type", + FormEditor_page_type_default_label: "Default", + FormEditor_page_type_summary_label: "Summary", + FormEditor_page_title_field_label: "Page title", + FormEditor_page_title_empty_text: "Enter page title", + FormEditor_page_tab_moveUp_text: "Move the current Page to the right", + FormEditor_page_tab_moveDown_text: "Move the current Page to the left", + FormEditor_page_tab_delete_text: "Delete the current page", + FormEditor_page_tab_insertBefore_text: "Insert a new page on the left", + FormEditor_page_tab_insertAfter_text: "Insert a new page on the right", }; export default FormEditor_properties; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/bundles/FormValidation_de_properties.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/bundles/FormValidation_de_properties.ts index aa06bfd2..d6d94bc0 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/bundles/FormValidation_de_properties.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/bundles/FormValidation_de_properties.ts @@ -21,8 +21,12 @@ ResourceBundleUtil.override(FormValidation_properties, { Validator_checkboxes_options_max_lower_min_text: "Bei den Checkboxen '{0}' darf die 'Min. Auswahl' nicht größer als die 'Max. Auswahl' sein.", Validator_selectbox_missing_options_text: "Die DropDown-Liste '{0}' muss mindestens eine Option haben.", Validator_formField_missing_name_text: "Das Formular-Element vom Typ '{0}' muss einen Namen haben.", + Validator_formField_ordering_error_text: "Es gab einen Fehler in der Datenstruktur. Bitte kontaktieren Sie einen Administrator.", + Validator_formField_summaryPage_multiple_error_text: "Eine Zusammenfassung kann nur einmal verwendet werden.", + Validator_formField_summaryPage_middle_error_text: "Eine Zusammenfassung muss als letzte Seite konfiguriert werden.", Validator_formfield_validator_invalid_minsize_text: "Der Validator des Formular-Elements '{0}' hat eine invalide minimale Größe: '{1}'.", Validator_formfield_validator_invalid_maxsize_text: "Der Validator des Formular-Elements '{0}' hat eine invalide maximale Größe: '{1}'.", Validator_formfield_validator_maxsize_smaller_minsize_text: "Der Validator des Formular-Elements '{0}' nutzt eine minimale Größe, die größer als die maximale Größe ist.", Validator_formfield_validator_invalid_regexp_text: "Der Validator des Formular-Elements '{0}' nutzt einen invaliden regulären Ausdruck.", + Validator_formfield_validator_duplicate_id_text: "Zwei Felder mit der selben Id '{0}' sind nicht gültig! Bitte beachten Sie auch die Custom-Id (Erweiterte Einstellungen).", }); diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/bundles/FormValidation_properties.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/bundles/FormValidation_properties.ts index ed13ff01..e7e36a4b 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/bundles/FormValidation_properties.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/bundles/FormValidation_properties.ts @@ -23,10 +23,14 @@ interface FormValidation_properties { Validator_checkboxes_options_max_lower_min_text: string; Validator_selectbox_missing_options_text: string; Validator_formField_missing_name_text: string; + Validator_formField_ordering_error_text: string; + Validator_formField_summaryPage_multiple_error_text: string; + Validator_formField_summaryPage_middle_error_text: string; Validator_formfield_validator_invalid_minsize_text: string; Validator_formfield_validator_invalid_maxsize_text: string; Validator_formfield_validator_maxsize_smaller_minsize_text: string; Validator_formfield_validator_invalid_regexp_text: string; + Validator_formfield_validator_duplicate_id_text: string; } /** @@ -49,10 +53,14 @@ const FormValidation_properties: FormValidation_properties = { Validator_checkboxes_options_max_lower_min_text: "Please check the field '{0}'. The min. selection should be lower than max. selection.", Validator_selectbox_missing_options_text: "The DropDown '{0}' must have at least one option.", Validator_formField_missing_name_text: "The FormField of the type '{0}' must have a name, please enter one.", + Validator_formField_ordering_error_text: "An error occurred in the data structure. Please contact an administrator.", + Validator_formField_summaryPage_multiple_error_text: "A summary page cannot be used more than once", + Validator_formField_summaryPage_middle_error_text: "A summary page must be the last page", Validator_formfield_validator_invalid_minsize_text: "The validator of the FormField '{0}' has an invalid minSize: '{1}'.", Validator_formfield_validator_invalid_maxsize_text: "The validator of the FormField '{0}' has an invalid maxSize: '{1}'.", Validator_formfield_validator_maxsize_smaller_minsize_text: "The validator of the FormField '{0}' has a minSize which is greater than the maxSize.", Validator_formfield_validator_invalid_regexp_text: "The validator of the FormField '{0}' uses an invalid regular expression to validate the input.", + Validator_formfield_validator_duplicate_id_text: "Two fields with the same Id '{0}' are not valid! Please remind the customIds (AdvancedSettings).", }; export default FormValidation_properties; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/components/StateFulCollapsiblePanel.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/components/StateFulCollapsiblePanel.ts index 06b5247b..a604f8c3 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/components/StateFulCollapsiblePanel.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/components/StateFulCollapsiblePanel.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import Config from "@jangaroo/runtime/Config"; import ConfigUtils from "@jangaroo/runtime/ConfigUtils"; import FormEditor_properties from "../bundles/FormEditor_properties"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/dragdrop/FormElementDropContainer.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/dragdrop/FormElementDropContainer.ts index 7c146296..5a832809 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/dragdrop/FormElementDropContainer.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/dragdrop/FormElementDropContainer.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import ValueExpression from "@coremedia/studio-client.client-core/data/ValueExpression"; import BEMPlugin from "@coremedia/studio-client.ext.ui-components/plugins/BEMPlugin"; import Editor_properties from "@coremedia/studio-client.main.editor-components/Editor_properties"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/dragdrop/FormElementDropContainerBase.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/dragdrop/FormElementDropContainerBase.ts index 4b84e75c..bd4b4286 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/dragdrop/FormElementDropContainerBase.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/dragdrop/FormElementDropContainerBase.ts @@ -67,7 +67,9 @@ class FormElementDropContainerBase extends Container { } override destroy(...params): void { - this.#dropTarget.unreg(); + if (this.#dropTarget) { + this.#dropTarget.unreg(); + } super.destroy(params); } diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/dragdrop/FormElementDropTarget.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/dragdrop/FormElementDropTarget.ts index ff79638f..b1f43a26 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/dragdrop/FormElementDropTarget.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/dragdrop/FormElementDropTarget.ts @@ -65,7 +65,6 @@ class FormElementDropTarget extends DropTarget { return true; } - trace("[ERROR] - Form element drop mode: " + mode + " not supported."); return false; } diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/dragdrop/FormElementDroppable.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/dragdrop/FormElementDroppable.ts index 31384d1e..acf1a28e 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/dragdrop/FormElementDroppable.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/dragdrop/FormElementDroppable.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import ValueExpression from "@coremedia/studio-client.client-core/data/ValueExpression"; import IconDisplayField from "@coremedia/studio-client.ext.ui-components/components/IconDisplayField"; import Container from "@jangaroo/ext-ts/container/Container"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/AbstractFormElement.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/AbstractFormElement.ts index 1045d42f..7b1e7e1e 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/AbstractFormElement.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/AbstractFormElement.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import ValueExpression from "@coremedia/studio-client.client-core/data/ValueExpression"; import Config from "@jangaroo/runtime/Config"; import ConfigUtils from "@jangaroo/runtime/ConfigUtils"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/AbstractFormElementBase.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/AbstractFormElementBase.ts index 6de8563f..b126bf9b 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/AbstractFormElementBase.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/AbstractFormElementBase.ts @@ -19,11 +19,13 @@ import ValueExpressionFactory from "@coremedia/studio-client.client-core/data/Va import ValueExpressionValueHolder from "@coremedia/studio-client.client-core/data/ValueExpressionValueHolder"; import ObservableUtil from "@coremedia/studio-client.ext.ui-components/util/ObservableUtil"; import Container from "@jangaroo/ext-ts/container/Container"; -import { mixin } from "@jangaroo/runtime"; +import {mixin} from "@jangaroo/runtime"; import Config from "@jangaroo/runtime/Config"; import FormElementStructWrapper from "../model/FormElementStructWrapper"; import AbstractFormElement from "./AbstractFormElement"; import FormElement from "./FormElement"; +import Bean from "@coremedia/studio-client.client-core/data/Bean"; +import beanFactory from "@coremedia/studio-client.client-core/data/beanFactory"; interface AbstractFormElementBaseConfig extends Config { } @@ -32,6 +34,11 @@ class AbstractFormElementBase extends Container implements FormElement { declare Config: AbstractFormElementBaseConfig; static readonly #FORM_ELEMENT_UPDATE_EVT: string = "formElementUpdated"; + static readonly FORM_ELEMENTS_STRUCT: string = "formElementStructVE"; + static readonly BIND_TO: string = "bindTo"; + static readonly FORCE_READ_ONLY_VE: string = "forceReadOnlyVE"; + static readonly FORM_ISSUES_VE: string = "formIssuesVE"; + static readonly PROPERTY_PATH_VE: string = "propertyPathVE"; #group: string = null; @@ -41,21 +48,13 @@ class AbstractFormElementBase extends Container implements FormElement { #structWrapper: FormElementStructWrapper = null; - #formElementStructVE: ValueExpression = null; - - #bindTo: ValueExpression = null; - - #forceReadOnlyValueExpression: ValueExpression = null; - - #formIssuesVE: ValueExpression = null; - - #propertyPathVE: ValueExpression = null; + #localBean: Bean = null; constructor(config: Config = null) { if (!config.formElementType) { throw new Error("Config formElementType is missing."); } - super((()=>{ + super((() => { this.#elementType = config.formElementType; this.#iconCls = config.formElementIconCls; //using the default value "other". @@ -78,10 +77,10 @@ class AbstractFormElementBase extends Container implements FormElement { updateFormElementStructWrapper(wrapper: FormElementStructWrapper): void { this.#structWrapper = wrapper; - this.#formElementStructVE = wrapper.getFormElementVE(); - this.#bindTo = wrapper.getBindTo(); - this.#forceReadOnlyValueExpression = wrapper.getForceReadOnlyValueExpression(); - this.#propertyPathVE = ValueExpressionFactory.createFromValue(wrapper.getPropertyPath()); + this.getLocalBean().set(AbstractFormElementBase.FORM_ELEMENTS_STRUCT, wrapper.getFormElementVE()); + this.getLocalBean().set(AbstractFormElementBase.BIND_TO, wrapper.getBindTo()); + this.getLocalBean().set(AbstractFormElementBase.FORCE_READ_ONLY_VE, wrapper.getForceReadOnlyValueExpression()); + this.getLocalBean().set(AbstractFormElementBase.PROPERTY_PATH_VE, ValueExpressionFactory.createFromValue(wrapper.getPropertyPath())); this.fireEvent(AbstractFormElementBase.#FORM_ELEMENT_UPDATE_EVT); } @@ -89,89 +88,53 @@ class AbstractFormElementBase extends Container implements FormElement { return this.#structWrapper; } - /** - * Since the editors for form elements are reused, the component is created without a form element struct value - * expression. As soon as the method updateFormElementStructWrapper is called and the form element is updated, a new - * value expression is returned. This is necessary so that the binding to the correct struct works after the update. - */ - getFormElementStructVE(): ValueExpression { - if (!this.#formElementStructVE) { - this.#formElementStructVE = ValueExpressionFactory.createFromValue(); + getLocalBean(): Bean { + if (!this.#localBean) { + this.#localBean = beanFactory._.createLocalBean(); + this.#localBean.set(AbstractFormElementBase.FORM_ELEMENTS_STRUCT, ValueExpressionFactory.createFromValue()); + this.#localBean.set(AbstractFormElementBase.BIND_TO, ValueExpressionFactory.createFromValue()); + this.#localBean.set(AbstractFormElementBase.FORCE_READ_ONLY_VE, ValueExpressionFactory.createFromValue()); + this.#localBean.set(AbstractFormElementBase.PROPERTY_PATH_VE, ValueExpressionFactory.createFromValue("")); + this.#localBean.set(AbstractFormElementBase.FORM_ISSUES_VE, this.getBindTo().extendBy(["issues", "byProperty"])); } - const self = this; - return ValueExpressionFactory.createFromFunction((): ValueExpressionValueHolder => { - ObservableUtil.dependOn(self, AbstractFormElementBase.#FORM_ELEMENT_UPDATE_EVT); - return new ValueExpressionValueHolder(this.#formElementStructVE); - }); + return this.#localBean; + } + + getFormElementStructVE(): ValueExpression { + return this.getValueExpression(AbstractFormElementBase.FORM_ELEMENTS_STRUCT); } - /** - * Since the editors for form elements are reused, the component is created without a bindTo value expression. As - * soon as the method updateFormElementStructWrapper is called and the form element is updated, a new - * value expression is returned. This is necessary so that the binding to the correct bindTo works after the update. - */ getBindTo(): ValueExpression { - if (!this.#bindTo) { - this.#bindTo = ValueExpressionFactory.createFromValue(); - } - const self = this; - return ValueExpressionFactory.createFromFunction((): ValueExpressionValueHolder => { - ObservableUtil.dependOn(self, AbstractFormElementBase.#FORM_ELEMENT_UPDATE_EVT); - return new ValueExpressionValueHolder(this.#bindTo); - }); + return this.getValueExpression(AbstractFormElementBase.BIND_TO); } - /** - * Since the editors for form elements are reused, the component is created without a forceReadOnlyValueExpression - * value expression. As soon as the method updateFormElementStructWrapper is called and the form element is updated, - * a new value expression is returned. This is necessary so that the binding to the correct - * forceReadOnlyValueExpression works after the update. - */ getForceReadOnlyVE(): ValueExpression { - if (!this.#forceReadOnlyValueExpression) { - this.#forceReadOnlyValueExpression = ValueExpressionFactory.createFromValue(); - } - const self = this; - return ValueExpressionFactory.createFromFunction((): ValueExpressionValueHolder => { - ObservableUtil.dependOn(self, AbstractFormElementBase.#FORM_ELEMENT_UPDATE_EVT); - return new ValueExpressionValueHolder(this.#forceReadOnlyValueExpression); - }); + return this.getValueExpression(AbstractFormElementBase.FORCE_READ_ONLY_VE); } - /** - * Since the editors for form elements are reused, the component is created without a - * form issues value expression. As soon as the method updateFormElementStructWrapper is called and - * the form element is updated, a new value expression is returned. This is necessary so that the binding to the - * correct formIssuesVE works after the update. - */ getFormIssuesVE(): ValueExpression { - if (!this.#formIssuesVE) { - this.#formIssuesVE = this.getBindTo().extendBy(["issues", "byProperty"]); - } - const self = this; - return ValueExpressionFactory.createFromFunction((): ValueExpressionValueHolder => { - ObservableUtil.dependOn(self, AbstractFormElementBase.#FORM_ELEMENT_UPDATE_EVT); - return new ValueExpressionValueHolder(this.#formIssuesVE); - }); + return this.getValueExpression(AbstractFormElementBase.FORM_ISSUES_VE); + } + + getPropertyPathVE(): ValueExpression { + return this.getValueExpression(AbstractFormElementBase.PROPERTY_PATH_VE); } /** - * Since the editors for form elements are reused, the component is created without a - * form issues value expression. As soon as the method updateFormElementStructWrapper is called and - * the form element is updated, a new value expression is returned. This is necessary so that the binding to the - * correct propertyPathVE works after the update. + * Since the editors for form elements are reused, the component is created with default values for all value + * expressions (see #getLocalBean() creation). As soon as the method updateFormElementStructWrapper is called and the + * form element is updated, a new value expression is returned. This is necessary so that the binding to the correct + * value expression works after the update. */ - getPropertyPathVE(): ValueExpression { - if (!this.#propertyPathVE) { - this.#propertyPathVE = ValueExpressionFactory.createFromValue(""); - } - const self = this; + getValueExpression(key: String): ValueExpression { + var self = this; return ValueExpressionFactory.createFromFunction((): ValueExpressionValueHolder => { ObservableUtil.dependOn(self, AbstractFormElementBase.#FORM_ELEMENT_UPDATE_EVT); - return new ValueExpressionValueHolder(this.#propertyPathVE); + return new ValueExpressionValueHolder(this.getLocalBean().get(key)); }); } } + mixin(AbstractFormElementBase, FormElement); export default AbstractFormElementBase; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/CheckBoxesEditor.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/CheckBoxesEditor.ts index 65d1b04b..a3c67379 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/CheckBoxesEditor.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/CheckBoxesEditor.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import SvgIconUtil from "@coremedia/studio-client.base-models/util/SvgIconUtil"; import Config from "@jangaroo/runtime/Config"; import ConfigUtils from "@jangaroo/runtime/ConfigUtils"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/ConsentFormCheckBoxEditor.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/ConsentFormCheckBoxEditor.ts index f094838c..1d5366cb 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/ConsentFormCheckBoxEditor.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/ConsentFormCheckBoxEditor.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import SvgIconUtil from "@coremedia/studio-client.base-models/util/SvgIconUtil"; import Config from "@jangaroo/runtime/Config"; import ConfigUtils from "@jangaroo/runtime/ConfigUtils"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/DateFieldEditor.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/DateFieldEditor.ts index 778a6ec7..5a1faf25 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/DateFieldEditor.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/DateFieldEditor.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import SvgIconUtil from "@coremedia/studio-client.base-models/util/SvgIconUtil"; import Config from "@jangaroo/runtime/Config"; import ConfigUtils from "@jangaroo/runtime/ConfigUtils"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/ElementGroupEntry.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/ElementGroupEntry.ts index 6fd028bb..0a926ec7 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/ElementGroupEntry.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/ElementGroupEntry.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import ValueExpression from "@coremedia/studio-client.client-core/data/ValueExpression"; import IconButton from "@coremedia/studio-client.ext.ui-components/components/IconButton"; import BEMPlugin from "@coremedia/studio-client.ext.ui-components/plugins/BEMPlugin"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/FileUploadEditor.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/FileUploadEditor.ts index be3c570a..e494ac8a 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/FileUploadEditor.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/FileUploadEditor.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import SvgIconUtil from "@coremedia/studio-client.base-models/util/SvgIconUtil"; import Config from "@jangaroo/runtime/Config"; import ConfigUtils from "@jangaroo/runtime/ConfigUtils"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/FormElement.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/FormElement.ts index 459bec3b..1334ab8a 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/FormElement.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/FormElement.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import ValueExpression from "@coremedia/studio-client.client-core/data/ValueExpression"; import FormElementStructWrapper from "../model/FormElementStructWrapper"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/HiddenFieldEditor.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/HiddenFieldEditor.ts new file mode 100644 index 00000000..f6a980f3 --- /dev/null +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/HiddenFieldEditor.ts @@ -0,0 +1,59 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import SvgIconUtil from "@coremedia/studio-client.base-models/util/SvgIconUtil"; +import Config from "@jangaroo/runtime/Config"; +import ConfigUtils from "@jangaroo/runtime/ConfigUtils"; +import FormEditor_properties from "../bundles/FormEditor_properties"; +import TextField from "../fields/TextField"; +import AdvancedSettingsField from "../fields/advancedsettings/AdvancedSettingsField"; +import Icon from "../icons/input-hidden.svg"; +import AbstractFormElement from "./AbstractFormElement"; + +interface HiddenFieldEditorConfig extends Config { +} + +class HiddenFieldEditor extends AbstractFormElement { + declare Config: HiddenFieldEditorConfig; + + static override readonly xtype: string = "com.tallence.formeditor.studio.elements.hiddenFieldEditor"; + + static readonly FIELD_TYPE: string = "HiddenField"; + + constructor(config: Config = null) { + super(ConfigUtils.apply(Config(HiddenFieldEditor, { + formElementType: HiddenFieldEditor.FIELD_TYPE, + formElementIconCls: SvgIconUtil.getIconStyleClassForSvgIcon(Icon), + formElementGroup: "input", + + items: [ + Config(TextField, { + fieldLabel: FormEditor_properties.FormEditor_element_name_label, + emptyText: FormEditor_properties.FormEditor_element_name_emptyText, + propertyName: "name", + }), + Config(TextField, { + fieldLabel: FormEditor_properties.FormEditor_element_hiddenField_value_label, + emptyText: FormEditor_properties.FormEditor_element_hiddenField_value_emptyText, + propertyName: "value", + }), + Config(AdvancedSettingsField, { propertyName: "advancedSettings" }), + ], + }), config)); + } +} + +export default HiddenFieldEditor; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/IbanFieldEditor.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/IbanFieldEditor.ts new file mode 100644 index 00000000..eba944b8 --- /dev/null +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/IbanFieldEditor.ts @@ -0,0 +1,54 @@ +import SvgIconUtil from "@coremedia/studio-client.base-models/util/SvgIconUtil"; +import Config from "@jangaroo/runtime/Config"; +import ConfigUtils from "@jangaroo/runtime/ConfigUtils"; +import FormEditor_properties from "../bundles/FormEditor_properties"; +import CheckboxField from "../fields/CheckboxField"; +import TextField from "../fields/TextField"; +import AdvancedSettingsField from "../fields/advancedsettings/AdvancedSettingsField"; +import Icon from "../icons/input-iban.svg"; +import AbstractFormElement from "./AbstractFormElement"; + +interface IbanFieldEditorConfig extends Config { +} + +class IbanFieldEditor extends AbstractFormElement { + declare Config: IbanFieldEditorConfig; + + static override readonly xtype: string = "com.tallence.formeditor.studio.elements.ibanFieldEditor"; + + static readonly FIELD_TYPE: string = "IbanField"; + + protected config: Config = null; + + constructor(config: Config = null) { + super(ConfigUtils.apply(Config(IbanFieldEditor, { + formElementType: IbanFieldEditor.FIELD_TYPE, + formElementIconCls: SvgIconUtil.getIconStyleClassForSvgIcon(Icon), + formElementGroup: "input", + + items: [ + Config(TextField, { + fieldLabel: FormEditor_properties.FormEditor_element_name_label, + emptyText: FormEditor_properties.FormEditor_element_name_emptyText, + propertyName: "name", + }), + + Config(TextField, { + fieldLabel: FormEditor_properties.FormEditor_element_hint_label, + emptyText: FormEditor_properties.FormEditor_element_hint_emptyText, + propertyName: "hint", + }), + + Config(CheckboxField, { + fieldLabel: FormEditor_properties.FormEditor_element_mandatory_label, + propertyName: "validator.mandatory", + defaultValue: false, + }), + + Config(AdvancedSettingsField, { propertyName: "advancedSettings" }), + ], + }), config)); + } +} + +export default IbanFieldEditor; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/NumberFieldEditor.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/NumberFieldEditor.ts index 900f710b..777635a5 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/NumberFieldEditor.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/NumberFieldEditor.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import SvgIconUtil from "@coremedia/studio-client.base-models/util/SvgIconUtil"; import Config from "@jangaroo/runtime/Config"; import ConfigUtils from "@jangaroo/runtime/ConfigUtils"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/PageElementEditor.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/PageElementEditor.ts new file mode 100644 index 00000000..5f0ee5a5 --- /dev/null +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/PageElementEditor.ts @@ -0,0 +1,60 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Config from "@jangaroo/runtime/Config"; +import ConfigUtils from "@jangaroo/runtime/ConfigUtils"; +import AbstractFormElement from "./AbstractFormElement"; +import TextField from "../fields/TextField"; +import FormEditor_properties from "../bundles/FormEditor_properties"; +import ComboBoxField from "../fields/ComboBoxField"; + +interface PageElementEditorConfig extends Config { +} + +class PageElementEditor extends AbstractFormElement { + declare Config: PageElementEditorConfig; + + static override readonly xtype: string = "com.tallence.formeditor.studio.elements.pageElementEditor"; + + static readonly FIELD_TYPE: string = "PageElement"; + static readonly DEFAULT_PAGE: string = "DEFAULT_PAGE"; + static readonly SUMMARY_PAGE: string = "SUMMARY_PAGE"; + + constructor(config: Config = null) { + super(ConfigUtils.apply(Config(PageElementEditor, { + formElementType: PageElementEditor.FIELD_TYPE, + formElementGroup: "hidden", + items: [ + Config(TextField, { + fieldLabel: FormEditor_properties.FormEditor_page_title_field_label, + emptyText: FormEditor_properties.FormEditor_page_title_empty_text, + propertyName: "name" + }), + Config(ComboBoxField, { + fieldLabel: FormEditor_properties.FormEditor_page_type_field_label, + emptyText: FormEditor_properties.FormEditor_page_type_empty_text, + propertyName: "pageType", + store: [ + [PageElementEditor.DEFAULT_PAGE, FormEditor_properties.FormEditor_page_type_default_label], + [PageElementEditor.SUMMARY_PAGE, FormEditor_properties.FormEditor_page_type_summary_label] + ], + }) + ], + }), config)); + } +} + +export default PageElementEditor; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/RadioButtonsEditor.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/RadioButtonsEditor.ts index e96926cf..f1fdee27 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/RadioButtonsEditor.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/RadioButtonsEditor.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import SvgIconUtil from "@coremedia/studio-client.base-models/util/SvgIconUtil"; import Config from "@jangaroo/runtime/Config"; import ConfigUtils from "@jangaroo/runtime/ConfigUtils"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/SelectBoxEditor.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/SelectBoxEditor.ts index 8d86e414..5b4ca014 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/SelectBoxEditor.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/SelectBoxEditor.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import SvgIconUtil from "@coremedia/studio-client.base-models/util/SvgIconUtil"; import Config from "@jangaroo/runtime/Config"; import ConfigUtils from "@jangaroo/runtime/ConfigUtils"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/TextAreaEditor.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/TextAreaEditor.ts index d9e47256..cec77d1e 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/TextAreaEditor.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/TextAreaEditor.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import SvgIconUtil from "@coremedia/studio-client.base-models/util/SvgIconUtil"; import Config from "@jangaroo/runtime/Config"; import ConfigUtils from "@jangaroo/runtime/ConfigUtils"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/TextFieldEditor.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/TextFieldEditor.ts index b7104af1..d6ce7874 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/TextFieldEditor.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/TextFieldEditor.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import SvgIconUtil from "@coremedia/studio-client.base-models/util/SvgIconUtil"; import Config from "@jangaroo/runtime/Config"; import ConfigUtils from "@jangaroo/runtime/ConfigUtils"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/TextOnlyEditor.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/TextOnlyEditor.ts index 5ce40940..fa10912c 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/TextOnlyEditor.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/TextOnlyEditor.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import SvgIconUtil from "@coremedia/studio-client.base-models/util/SvgIconUtil"; import Config from "@jangaroo/runtime/Config"; import ConfigUtils from "@jangaroo/runtime/ConfigUtils"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/UsersMailEditor.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/UsersMailEditor.ts index 81ebd425..2ba891de 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/UsersMailEditor.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/elements/UsersMailEditor.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import SvgIconUtil from "@coremedia/studio-client.base-models/util/SvgIconUtil"; import Config from "@jangaroo/runtime/Config"; import ConfigUtils from "@jangaroo/runtime/ConfigUtils"; @@ -55,6 +71,7 @@ class UsersMailEditor extends AbstractFormElement { Config(ComboBoxField, { fieldLabel: FormEditor_properties.FormEditor_usersMail_mailType_label, emptyText: FormEditor_properties.FormEditor_usersMail_mailType_label, + defaultValue: UsersMailEditor.COMBO_VALUE_NEVER, propertyName: "copyType", store: [ [ UsersMailEditor.COMBO_VALUE_CHECKBOX, FormEditor_properties.FormEditor_usersMail_mailType_checkbox ], diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/AddOptionField.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/AddOptionField.ts index e4be6c79..1def4c57 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/AddOptionField.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/AddOptionField.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import IconButton from "@coremedia/studio-client.ext.ui-components/components/IconButton"; import StatefulTextField from "@coremedia/studio-client.ext.ui-components/components/StatefulTextField"; import BindComponentsPlugin from "@coremedia/studio-client.ext.ui-components/plugins/BindComponentsPlugin"; @@ -14,6 +30,7 @@ import ElementGroupEntry from "../elements/ElementGroupEntry"; import ShowFormIssuesPlugin from "../plugins/ShowFormIssuesPlugin"; import AddOptionFieldBase from "./AddOptionFieldBase"; import CoreIcons_properties from "@coremedia/studio-client.core-icons/CoreIcons_properties"; +import FormUtils from "../FormUtils"; interface AddOptionFieldConfig extends Config { } @@ -64,6 +81,11 @@ class AddOptionField extends AddOptionFieldBase { bindTo: config.bindTo, forceReadOnlyValueExpression: this.getAddOptionButtonDisabledVE(), }), + Config(BindPropertyPlugin, { + componentProperty: "tooltip", + transformer: function(disabled:Boolean):String { return FormUtils.getOptionRemoveButtonToolTip(disabled); }, + bindTo: this.getAddOptionButtonDisabledVE(), + }), ], }), ], diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/AddOptionFieldBase.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/AddOptionFieldBase.ts index 59240a13..d8af1ea2 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/AddOptionFieldBase.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/AddOptionFieldBase.ts @@ -184,7 +184,7 @@ class AddOptionFieldBase extends FormEditorField { protected getAddOptionButtonDisabledVE(): ValueExpression { return ValueExpressionFactory.createFromFunction((): boolean => { const optionName: string = this.getAddOptionVE().getValue(); - return this.forceReadOnlyValueExpression.getValue() || optionName == null || !Format.trim(optionName).length; + return this.forceReadOnlyValueExpression.getValue() || !FormUtils.validateOptionValue(optionName); }); } diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/CheckboxField.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/CheckboxField.ts index f509e3fc..c0753aca 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/CheckboxField.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/CheckboxField.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import BindPropertyPlugin from "@coremedia/studio-client.ext.ui-components/plugins/BindPropertyPlugin"; import BindDisablePlugin from "@coremedia/studio-client.main.editor-components/sdk/premular/fields/plugins/BindDisablePlugin"; import FieldContainer from "@jangaroo/ext-ts/form/FieldContainer"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/ComboBoxField.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/ComboBoxField.ts index 08e7a381..ac884e90 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/ComboBoxField.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/ComboBoxField.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import LocalComboBox from "@coremedia/studio-client.ext.ui-components/components/LocalComboBox"; import BindPropertyPlugin from "@coremedia/studio-client.ext.ui-components/plugins/BindPropertyPlugin"; import BindDisablePlugin from "@coremedia/studio-client.main.editor-components/sdk/premular/fields/plugins/BindDisablePlugin"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/ComboBoxFieldBase.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/ComboBoxFieldBase.ts index f32a1ada..088d1b03 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/ComboBoxFieldBase.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/ComboBoxFieldBase.ts @@ -17,17 +17,36 @@ import Config from "@jangaroo/runtime/Config"; import FormEditorField from "./FormEditorField"; import TextFieldBase from "./TextFieldBase"; +import ValueExpression from "@coremedia/studio-client.client-core/data/ValueExpression"; -interface ComboBoxFieldBaseConfig extends Config { +interface ComboBoxFieldBaseConfig extends Config, Partial> { } class ComboBoxFieldBase extends FormEditorField { declare Config: ComboBoxFieldBaseConfig; - constructor(config: Config = null) { + #defaultValue: string = ""; + + get defaultValue(): string { + return this.#defaultValue; + } + + set defaultValue(value: string) { + this.#defaultValue = value; + } + + constructor(config: Config = null) { super(config); } + protected override initWithDefault(ve: ValueExpression): void { + if (this.defaultValue != undefined) { + ve.setValue(this.defaultValue); + } + } + } export default ComboBoxFieldBase; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/EditOptionWindow.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/EditOptionWindow.ts index a84136e9..8187152a 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/EditOptionWindow.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/EditOptionWindow.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import IconButton from "@coremedia/studio-client.ext.ui-components/components/IconButton"; import StatefulTextField from "@coremedia/studio-client.ext.ui-components/components/StatefulTextField"; import BindPropertyPlugin from "@coremedia/studio-client.ext.ui-components/plugins/BindPropertyPlugin"; @@ -18,6 +34,7 @@ import ConfigUtils from "@jangaroo/runtime/ConfigUtils"; import resourceManager from "@jangaroo/runtime/l10n/resourceManager"; import FormEditor_properties from "../bundles/FormEditor_properties"; import EditOptionWindowBase from "./EditOptionWindowBase"; +import FormUtils from "../FormUtils"; interface EditOptionWindowConfig extends Config { } @@ -119,6 +136,11 @@ class EditOptionWindow extends EditOptionWindowBase { componentProperty: "disabled", bindTo: this.getSaveButtonDisabledVE(), }), + Config(BindPropertyPlugin, { + componentProperty: "tooltip", + transformer: function(disabled:Boolean):String { return FormUtils.getOptionRemoveButtonToolTip(disabled); }, + bindTo: this.getSaveButtonDisabledVE(), + }), ], }), diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/EditOptionWindowBase.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/EditOptionWindowBase.ts index 09c26808..ef135fb0 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/EditOptionWindowBase.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/EditOptionWindowBase.ts @@ -16,12 +16,12 @@ import ValueExpression from "@coremedia/studio-client.client-core/data/ValueExpression"; import ValueExpressionFactory from "@coremedia/studio-client.client-core/data/ValueExpressionFactory"; -import Format from "@jangaroo/ext-ts/util/Format"; import Window from "@jangaroo/ext-ts/window/Window"; import Config from "@jangaroo/runtime/Config"; import {AnyFunction} from "@jangaroo/runtime/types"; import GroupElementStructWrapper from "../model/GroupElementStructWrapper"; import EditOptionWindow from "./EditOptionWindow"; +import FormUtils from "../FormUtils"; interface EditOptionWindowBaseConfig extends Config, Partial> { @@ -100,7 +100,7 @@ class EditOptionWindowBase extends Window { protected getSaveButtonDisabledVE(): ValueExpression { return ValueExpressionFactory.createFromFunction((): boolean => { const displayName: string = this.getOptionNameVE().getValue(); - return displayName == null || !Format.trim(displayName).length; + return !FormUtils.validateOptionValue(displayName); }); } diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/FormEditorField.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/FormEditorField.ts index bccdf3ed..7be3f2b6 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/FormEditorField.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/FormEditorField.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import ValueExpression from "@coremedia/studio-client.client-core/data/ValueExpression"; import Config from "@jangaroo/runtime/Config"; import ConfigUtils from "@jangaroo/runtime/ConfigUtils"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/FormEditorFieldBase.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/FormEditorFieldBase.ts index 45cca813..09c26f95 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/FormEditorFieldBase.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/FormEditorFieldBase.ts @@ -39,6 +39,8 @@ class FormEditorFieldBase extends Container { #propertyName: string = null; + #formElementStructVE: ValueExpression = null; + constructor(config: Config = null) { super(config); this.#initFormEditorField(config); @@ -53,9 +55,9 @@ class FormEditorFieldBase extends Container { this.#propertyName = config.propertyName; this.#bindTo = config.bindTo; this.#forceReadOnlyVE = config.forceReadOnlyValueExpression; - const formElementStructVE = config.formElementStructVE; - formElementStructVE.addChangeListener(bind(this, this.#onFormElementStructChange)); - this.#updatePropertyVE(formElementStructVE); + this.#formElementStructVE = config.formElementStructVE; + this.#formElementStructVE.addChangeListener(bind(this, this.#onFormElementStructChange)); + this.#updatePropertyVE(this.#formElementStructVE); } } @@ -128,6 +130,12 @@ class FormEditorFieldBase extends Container { struct.getType().addStructProperty("validator"); } } + + + override destroy(...args): any { + this.#formElementStructVE.removeChangeListener(this.#onFormElementStructChange); + return super.destroy(...args); + } } export default FormEditorFieldBase; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/LinkedContentField.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/LinkedContentField.ts index 02cb0297..bccc4719 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/LinkedContentField.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/LinkedContentField.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import SingleLinkEditor from "@coremedia/studio-client.main.editor-components/sdk/premular/fields/SingleLinkEditor"; import BindDisablePlugin from "@coremedia/studio-client.main.editor-components/sdk/premular/fields/plugins/BindDisablePlugin"; import AnchorLayout from "@jangaroo/ext-ts/layout/container/Anchor"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/NumberField.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/NumberField.ts index 2b4b485a..ae32b98b 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/NumberField.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/NumberField.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import StatefulNumberField from "@coremedia/studio-client.ext.ui-components/components/StatefulNumberField"; import BindPropertyPlugin from "@coremedia/studio-client.ext.ui-components/plugins/BindPropertyPlugin"; import BindDisablePlugin from "@coremedia/studio-client.main.editor-components/sdk/premular/fields/plugins/BindDisablePlugin"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/SingleLinkValueExpressionHolder.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/SingleLinkValueExpressionHolder.ts index 2599227a..308746d5 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/SingleLinkValueExpressionHolder.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/SingleLinkValueExpressionHolder.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import ValueExpression from "@coremedia/studio-client.client-core/data/ValueExpression"; import ValueHolder from "@coremedia/studio-client.client-core/data/ValueHolder"; import { mixin } from "@jangaroo/runtime"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/TextField.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/TextField.ts index 54ae485d..49bf7761 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/TextField.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/TextField.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import StatefulTextField from "@coremedia/studio-client.ext.ui-components/components/StatefulTextField"; import BindPropertyPlugin from "@coremedia/studio-client.ext.ui-components/plugins/BindPropertyPlugin"; import BindDisablePlugin from "@coremedia/studio-client.main.editor-components/sdk/premular/fields/plugins/BindDisablePlugin"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/advancedsettings/AdvancedSettingsField.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/advancedsettings/AdvancedSettingsField.ts index b2b2aea9..669375c3 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/advancedsettings/AdvancedSettingsField.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/advancedsettings/AdvancedSettingsField.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import CollapsiblePanel from "@coremedia/studio-client.main.editor-components/sdk/premular/CollapsiblePanel"; import TabPanel from "@jangaroo/ext-ts/tab/Panel"; import Config from "@jangaroo/runtime/Config"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/advancedsettings/tabs/AdvancedIdSettingsTab.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/advancedsettings/tabs/AdvancedIdSettingsTab.ts index 72f16cb8..401b0d61 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/advancedsettings/tabs/AdvancedIdSettingsTab.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/advancedsettings/tabs/AdvancedIdSettingsTab.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import StatefulTextField from "@coremedia/studio-client.ext.ui-components/components/StatefulTextField"; import BindPropertyPlugin from "@coremedia/studio-client.ext.ui-components/plugins/BindPropertyPlugin"; import BindDisablePlugin from "@coremedia/studio-client.main.editor-components/sdk/premular/fields/plugins/BindDisablePlugin"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/advancedsettings/tabs/AdvancedLayoutSettingsTab.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/advancedsettings/tabs/AdvancedLayoutSettingsTab.ts index 57919e04..133c2f4d 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/advancedsettings/tabs/AdvancedLayoutSettingsTab.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/advancedsettings/tabs/AdvancedLayoutSettingsTab.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import StatefulCheckbox from "@coremedia/studio-client.ext.ui-components/components/StatefulCheckbox"; import StatefulNumberField from "@coremedia/studio-client.ext.ui-components/components/StatefulNumberField"; import BindPropertyPlugin from "@coremedia/studio-client.ext.ui-components/plugins/BindPropertyPlugin"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/advancedsettings/tabs/AdvancedSettingsTab.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/advancedsettings/tabs/AdvancedSettingsTab.ts index 68fdcc04..7d4cbf59 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/advancedsettings/tabs/AdvancedSettingsTab.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/advancedsettings/tabs/AdvancedSettingsTab.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import ValueExpression from "@coremedia/studio-client.client-core/data/ValueExpression"; import DisplayFieldSkin from "@coremedia/studio-client.ext.ui-components/skins/DisplayFieldSkin"; import DisplayField from "@jangaroo/ext-ts/form/field/Display"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/advancedsettings/tabs/AdvancedVisibilitySettingsTab.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/advancedsettings/tabs/AdvancedVisibilitySettingsTab.ts index 264f6ccb..0a77eb1c 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/advancedsettings/tabs/AdvancedVisibilitySettingsTab.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/advancedsettings/tabs/AdvancedVisibilitySettingsTab.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import StatefulCheckbox from "@coremedia/studio-client.ext.ui-components/components/StatefulCheckbox"; import StatefulTextField from "@coremedia/studio-client.ext.ui-components/components/StatefulTextField"; import SwitchingContainer from "@coremedia/studio-client.ext.ui-components/components/SwitchingContainer"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/advancedsettings/tabs/AdvancedVisibilitySettingsTabBase.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/advancedsettings/tabs/AdvancedVisibilitySettingsTabBase.ts index f578c12b..6c651467 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/advancedsettings/tabs/AdvancedVisibilitySettingsTabBase.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/advancedsettings/tabs/AdvancedVisibilitySettingsTabBase.ts @@ -90,9 +90,13 @@ class AdvancedVisibilitySettingsTabBase extends AdvancedSettingsTab { if (selected && selected.length > 0) { const options: Struct = as(selected[0], FormElementStructWrapper).getFormElementVE().extendBy("groupElements").getValue(); if (options) { - return options.getType().getPropertyNames().map((value: string): any => - AdvancedVisibilitySettingsTabBase.#createComboBoxEntry(value, value), - ); + return options.getType().getPropertyNames().map((displayValue: string): any => { + + //Field with options, e.g. checkboxes/selectboxes/radiogroups may have an (optional) value set for each + //option entry. If so, use this one, otherwise use the displayed label + const internalValue: string = options.get(displayValue).get("value"); + return AdvancedVisibilitySettingsTabBase.#createComboBoxEntry(internalValue != null ? internalValue : displayValue, displayValue); + }); } } return []; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/advancedsettings/tabs/VisibilityComboBoxField.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/advancedsettings/tabs/VisibilityComboBoxField.ts index 41f80110..9b1916e3 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/advancedsettings/tabs/VisibilityComboBoxField.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/fields/advancedsettings/tabs/VisibilityComboBoxField.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import ValueExpression from "@coremedia/studio-client.client-core/data/ValueExpression"; import StatefulComboBox from "@coremedia/studio-client.ext.ui-components/components/StatefulComboBox"; import BindListPlugin from "@coremedia/studio-client.ext.ui-components/plugins/BindListPlugin"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/helper/FormElementsManager.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/helper/FormElementsManager.ts index acf588d0..6f14b67e 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/helper/FormElementsManager.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/helper/FormElementsManager.ts @@ -18,12 +18,15 @@ import Struct from "@coremedia/studio-client.cap-rest-client/struct/Struct"; import ValueExpression from "@coremedia/studio-client.client-core/data/ValueExpression"; import ValueExpressionFactory from "@coremedia/studio-client.client-core/data/ValueExpressionFactory"; import StructTreeNode from "@coremedia/studio-client.main.editor-components/sdk/premular/fields/struct/StructTreeNode"; -import StructTreeStore from "@coremedia/studio-client.main.editor-components/sdk/premular/fields/struct/StructTreeStore"; -import { as, bind } from "@jangaroo/runtime"; +import StructTreeStore + from "@coremedia/studio-client.main.editor-components/sdk/premular/fields/struct/StructTreeStore"; +import {as, bind} from "@jangaroo/runtime"; import Config from "@jangaroo/runtime/Config"; import int from "@jangaroo/runtime/int"; import FormElementStructWrapper from "../model/FormElementStructWrapper"; import NodeInterface from "@jangaroo/ext-ts/data/NodeInterface"; +import PageElementEditor from "../elements/PageElementEditor"; +import FormEditor_properties from "../bundles/FormEditor_properties"; class FormElementsManager { @@ -44,8 +47,8 @@ class FormElementsManager { #formElementsStruct: StructTreeNode = null; constructor(contentVE: ValueExpression, - forceReadOnlyValueExpression: ValueExpression, - formDataStructPropertyName: string) { + forceReadOnlyValueExpression: ValueExpression, + formDataStructPropertyName: string) { this.#contentVE = contentVE; this.#formDataStructPropertyName = formDataStructPropertyName; this.#dragActiveVE = ValueExpressionFactory.createFromValue(false); @@ -60,30 +63,78 @@ class FormElementsManager { return this.#formElementWrappersVE; } + static getPageInitialData(title: string, newElements: Record = null): Record { + return { + name: title, + type: PageElementEditor.FIELD_TYPE, + pageType: PageElementEditor.DEFAULT_PAGE, + validator: {}, + formElements: newElements ? newElements : {} + }; + + } + + addFormPage(referenceElementId: string, insertAfter: boolean = true): String { + return this.addElement(referenceElementId, FormElementsManager.getPageInitialData(FormEditor_properties.FormEditor_pages_new_title), insertAfter); + } + addFormElement(afterFormElementId: string, formElementType: string): void { const initialData: Record = { validator: {}, type: formElementType, }; - const id = FormElementsManager.#generateRandomId().toString(); + this.addElement(afterFormElementId, initialData); + } + + addElement(afterFormElementId: string, initialData: Record, insertAfter: boolean = true): String { + const id = FormElementsManager.generateRandomId().toString(); this.#getRootNodeStruct().getType().addStructProperty(id, initialData); - this.moveFormElement(afterFormElementId, id); + this.moveFormElement(afterFormElementId, id, insertAfter); //collapse all other FormElements and show the new one this.getCollapsedElementVE().setValue(id); + return id; + } + + /** + * Move the formElement, identified by the given id. + * @param formElementId the formElement to be moved + * @param moveUp true, if the element has to be move to the next index, false otherwise + */ + moveFormElementRelative(formElementId: string, moveUp: boolean = true): void { + const formElements = this.#getRootNodeStruct().getType(); + const formElementIds:string[] = formElements.getPropertyNames(); + let currentIndex = formElementIds.indexOf(formElementId); + + let referenceElementIndex = 0; + if (!moveUp) { + referenceElementIndex = currentIndex > 0 ? (currentIndex - 1) : 0; + } else { + referenceElementIndex = ((currentIndex + 1) == formElementIds.length) ? currentIndex : (currentIndex + 1) + } + this.moveFormElement(formElementIds[referenceElementIndex], formElementId, moveUp); + } /** * Moves the struct of the given formElementId to the new position. The element is moved after the struct of the - * given afterFormElementId. + * given referenceElement. */ - moveFormElement(afterFormElementId: string, formElementId: string): void { - if (formElementId != afterFormElementId) { + moveFormElement(referenceElement: string, formElementId: string, insertAfter: boolean = true): void { + + if (formElementId != referenceElement) { const formElements = this.#getRootNodeStruct().getType(); const formElementIds = formElements.getPropertyNames(); formElementIds.splice(formElementIds.indexOf(formElementId), 1); - const position: number = afterFormElementId != undefined ? formElementIds.indexOf(afterFormElementId) + 1 : 0; + + let position = 0; + if (referenceElement != undefined) { + let referenceIndex = formElementIds.indexOf(referenceElement); + referenceIndex = referenceIndex + (insertAfter ? 1 : 0); + position = referenceIndex >= 0 ? referenceIndex : 0; + } + formElementIds.splice(position, 0, formElementId); formElements.rearrangeProperties(formElementIds); } @@ -93,7 +144,7 @@ class FormElementsManager { this.#getRootNodeStruct().getType().removeProperty(elementId); } - static #generateRandomId(): number { + static generateRandomId(): number { return Math.floor(Math.random() * (int.MAX_VALUE - 0 + 1)) + 23; } @@ -140,6 +191,12 @@ class FormElementsManager { this.#formElementsWrapperStore.addListener("nodeappend", bind(this, this.#nodeAppended)); this.#formElementsWrapperStore.addListener("nodeinsert", bind(this, this.#nodeInserted)); this.#formElementsWrapperStore.addListener("noderemove", bind(this, this.#nodeRemoved)); + let formElements = this.#formElementsWrapperStore.getRoot().findChild("text", FormElementStructWrapper.FORM_ELEMENTS_PROPERTY); + if (formElements != null) { + this.#formElementsStruct = formElements; + this.#updateFormElements(); + } + } #nodeRemoved(_store: NodeInterface, record: NodeInterface): void { @@ -161,6 +218,7 @@ class FormElementsManager { #nodeAppended(store: NodeInterface, record: NodeInterface, _index: number): any { return this.#addNodeInternal(store, record); } + #addNodeInternal(_store: NodeInterface, record: NodeInterface): any { const depth = record.getDepth(); if (depth == 1 && record instanceof StructTreeNode) { @@ -174,16 +232,20 @@ class FormElementsManager { } #updateFormElements(): void { - const elements = this.#formElementsStruct.childNodes.map((node: StructTreeNode): FormElementStructWrapper => - new FormElementStructWrapper( - node, - this.#formDataStructPropertyName, - this.#contentVE, - this.#forceReadOnlyValueExpression), - ); + const elements = this.generateWrapper(this.#formElementsStruct.childNodes); this.getFormElementsVE().setValue(elements); } + generateWrapper(childNodes: NodeInterface[]): Array { + return childNodes.map((node: StructTreeNode): FormElementStructWrapper => + new FormElementStructWrapper( + node, + this.#formDataStructPropertyName, + this.#contentVE, + this.#forceReadOnlyValueExpression) + ); + } + } export default FormElementsManager; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/icons/input-hidden.svg b/apps/studio-client/apps/main/form-editor-studio-plugin/src/icons/input-hidden.svg new file mode 100644 index 00000000..e4a65e17 --- /dev/null +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/icons/input-hidden.svg @@ -0,0 +1,12 @@ + + + + diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/icons/input-iban.svg b/apps/studio-client/apps/main/form-editor-studio-plugin/src/icons/input-iban.svg new file mode 100644 index 00000000..edaebac4 --- /dev/null +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/icons/input-iban.svg @@ -0,0 +1,4 @@ + + + diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/model/FormElementStructWrapper.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/model/FormElementStructWrapper.ts index fbd53802..ac171174 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/model/FormElementStructWrapper.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/model/FormElementStructWrapper.ts @@ -26,7 +26,7 @@ class FormElementStructWrapper { static readonly FORM_ELEMENTS_PROPERTY: string = "formElements"; - static readonly #TYPE_PROPERTY: string = "type"; + static readonly TYPE_PROPERTY: string = "type"; #structPropertyName: string = null; @@ -50,7 +50,7 @@ class FormElementStructWrapper { this.#structPropertyName = structPropertyName; this.#id = node.getPropertyName(); this.#formElementVE = bindTo.extendBy(ContentPropertyNames.PROPERTIES, structPropertyName, FormElementStructWrapper.FORM_ELEMENTS_PROPERTY, this.#id); - this.#type = FormElementStructWrapper.#getStructStringProperty(node.getValueAsStruct(), FormElementStructWrapper.#TYPE_PROPERTY); + this.#type = FormElementStructWrapper.#getStructStringProperty(node.getValueAsStruct(), FormElementStructWrapper.TYPE_PROPERTY); this.#bindTo = bindTo; this.#forceReadOnlyValueExpression = forceReadOnlyValueExpression; } @@ -79,6 +79,10 @@ class FormElementStructWrapper { return this.#type; } + getNode(): StructTreeNode { + return this.#node; + } + /** * Returns the property path of the applied form element. * e.g. 'formData.formElements.320798398' diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/pages/FormPageTab.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/pages/FormPageTab.ts new file mode 100644 index 00000000..156f1688 --- /dev/null +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/pages/FormPageTab.ts @@ -0,0 +1,183 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Config from "@jangaroo/runtime/Config"; +import Panel from "@jangaroo/ext-ts/panel/Panel"; +import ConfigUtils from "@jangaroo/runtime/ConfigUtils"; +import ValueExpression from "@coremedia/studio-client.client-core/data/ValueExpression"; +import FormElementsManager from "../helper/FormElementsManager"; +import AppliedElementsContainer from "../AppliedElementsContainer"; +import FormElementStructWrapper from "../model/FormElementStructWrapper"; +import BindPropertyPlugin from "@coremedia/studio-client.ext.ui-components/plugins/BindPropertyPlugin"; +import Container from "@jangaroo/ext-ts/container/Container"; +import AppliedFormPageContainer from "../AppliedFormPageContainer"; +import HBoxLayout from "@jangaroo/ext-ts/layout/container/HBox"; +import {bind} from "@jangaroo/runtime"; +import IconButton from "@coremedia/studio-client.ext.ui-components/components/IconButton"; +import CoreIcons_properties from "@coremedia/studio-client.core-icons/CoreIcons_properties"; +import FormEditor_properties from "../bundles/FormEditor_properties"; + + +interface FormPageTabConfig extends Config, Partial> { +} + +/** + * TODO: implement all actions / button handlers + */ +class FormPageTab extends Panel { + declare Config: FormPageTabConfig; + static override readonly xtype: string = "com.tallence.formeditor.studio.config.formPageTab"; + + #bindTo: ValueExpression = null; + #forceReadOnlyValueExpression: ValueExpression = null; + #formElementsManager: FormElementsManager = null; + #page: FormElementStructWrapper = null; + #activeTabValueExpression: ValueExpression = null; + + get page(): FormElementStructWrapper { + return this.#page; + } + + get activeTabValueExpression(): ValueExpression { + return this.#activeTabValueExpression; + } + + get bindTo(): ValueExpression { + return this.#bindTo; + } + + get forceReadOnlyValueExpression(): ValueExpression { + return this.#forceReadOnlyValueExpression; + } + + get formElementsManager(): FormElementsManager { + return this.#formElementsManager; + } + + addPage() { + this.#addPageInternal(); + } + + addPageBefore() { + this.#addPageInternal(false); + } + + #addPageInternal(insertAfter: boolean = true) { + let newPageId:String = this.#formElementsManager.addFormPage(this.page.getId(), insertAfter); + if (this.#activeTabValueExpression){ + this.#activeTabValueExpression.setValue(this.buildPageId(newPageId)); + } + } + + movePageUp() { + let currentPageId = this.page.getId(); + this.#formElementsManager.moveFormElementRelative(currentPageId); + if (this.#activeTabValueExpression){ + this.#activeTabValueExpression.setValue(this.buildPageId(currentPageId)); + } + } + + movePageDown() { + let currentPageId = this.page.getId(); + this.#formElementsManager.moveFormElementRelative(currentPageId, false); + if (this.#activeTabValueExpression){ + this.#activeTabValueExpression.setValue(this.buildPageId(currentPageId)); + } + } + + removePage() { + this.#formElementsManager.removeFormElement(this.page.getId()) + this.#activeTabValueExpression.setValue(null); + } + + buildPageId(structId: String): string { + return "page-" + structId; + } + + constructor(config: Config = null) { + super((() => ConfigUtils.apply(Config(FormPageTab, { + title: config.page.getNode().getValueAsStruct().get("name"), + itemId: this.buildPageId(config.page.getId()), + plugins: [ + Config(BindPropertyPlugin, { + bidirectional: false, + componentProperty: "title", + bindTo: config.page.getFormElementVE().extendBy("name"), + }) + ], + dockedItems: [ + Config(Container, { + items: [ + Config(Container, { + layout: Config(HBoxLayout), + items: [ + Config(IconButton, { + iconCls: CoreIcons_properties.add, + tooltip: FormEditor_properties.FormEditor_page_tab_insertBefore_text, + handler: bind(this, this.addPageBefore) + }), + Config(IconButton, { + iconCls: CoreIcons_properties.arrow_left, + tooltip: FormEditor_properties.FormEditor_page_tab_moveDown_text, + handler: bind(this, this.movePageDown) + }), + Config(IconButton, { + iconCls: CoreIcons_properties.remove, + tooltip: FormEditor_properties.FormEditor_page_tab_delete_text, + handler: bind(this, this.removePage) + }), + Config(IconButton, { + iconCls: CoreIcons_properties.arrow_right, + tooltip: FormEditor_properties.FormEditor_page_tab_moveUp_text, + handler: bind(this, this.movePageUp) + }), + Config(IconButton, { + iconCls: CoreIcons_properties.add, + tooltip: FormEditor_properties.FormEditor_page_tab_insertAfter_text, + handler: bind(this, this.addPage) + }) + ] + }), + Config(AppliedFormPageContainer, { + bindTo: config.bindTo, + formElement: config.page, + forceReadOnlyValueExpression: config.forceReadOnlyValueExpression, + formElementsManager: config.formElementsManager, + }), + ] + }) + ], + items: [ + Config(AppliedElementsContainer, { + bindTo: config.bindTo, + forceReadOnlyValueExpression: config.forceReadOnlyValueExpression, + formElementsManager: new FormElementsManager(config.bindTo, config.forceReadOnlyValueExpression, "formData.formElements." + config.page.getId()) + }) + ], + + }), config))()); + this.#formElementsManager = config.formElementsManager; + this.#page = config.page; + this.#activeTabValueExpression = config.activeTabValueExpression; + } +} + +export default FormPageTab; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/pages/PagesWrapperContainer.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/pages/PagesWrapperContainer.ts new file mode 100644 index 00000000..6e78d7dc --- /dev/null +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/pages/PagesWrapperContainer.ts @@ -0,0 +1,108 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Config from "@jangaroo/runtime/Config"; +import ConfigUtils from "@jangaroo/runtime/ConfigUtils"; +import TabPanel from "@jangaroo/ext-ts/tab/Panel"; +import FormPageTab from "./FormPageTab"; +import BEMPlugin from "@coremedia/studio-client.ext.ui-components/plugins/BEMPlugin"; +import ValueExpression from "@coremedia/studio-client.client-core/data/ValueExpression"; +import FormElementsManager from "../helper/FormElementsManager"; +import ValueExpressionFactory from "@coremedia/studio-client.client-core/data/ValueExpressionFactory"; +import FormElementStructWrapper from "../model/FormElementStructWrapper"; +import BindComponentsPlugin from "@coremedia/studio-client.ext.ui-components/plugins/BindComponentsPlugin"; +import PageElementEditor from "../elements/PageElementEditor"; + +interface PagesWrapperContainerConfig extends Config, Partial> { +} + +class PagesWrapperContainer extends TabPanel { + + static override readonly xtype: string = "com.tallence.formeditor.studio.config.pagesWrapperContainer"; + + declare Config: PagesWrapperContainerConfig; + + #bindTo: ValueExpression = null; + #forceReadOnlyValueExpression: ValueExpression = null; + #formElementsManager: FormElementsManager = null; + #activeTabVE: ValueExpression = null; + + get bindTo(): ValueExpression { + return this.#bindTo; + } + + get forceReadOnlyValueExpression(): ValueExpression { + return this.#forceReadOnlyValueExpression; + } + + get formElementsManager(): FormElementsManager { + return this.#formElementsManager; + } + + getPages(config: PagesWrapperContainerConfig): ValueExpression { + return ValueExpressionFactory.createTransformingValueExpression(config.formElementsManager.getFormElementsVE(), ((elements: Array): Array => + elements.filter((element: FormElementStructWrapper): boolean => element.getType() == PageElementEditor.FIELD_TYPE) + )) + } + + getActiveTabVE(): ValueExpression { + if (!this.#activeTabVE) { + this.#activeTabVE = ValueExpressionFactory.createFromValue(null); + } + return this.#activeTabVE; + } + + constructor(config: Config = null) { + super((() => ConfigUtils.apply(Config(PagesWrapperContainer, { + bodyPadding: 20, + plugins: [ + Config(BEMPlugin, { + block: "form-page-container", + }), + Config(BindComponentsPlugin, { + configBeanParameterName: "page", + clearBeforeUpdate: true, + valueExpression: this.getPages(config), + afterUpdateCallback: this.onPageUpdate, + template: Config(FormPageTab, { + forceReadOnlyValueExpression: config.forceReadOnlyValueExpression, + bindTo: config.bindTo, + formElementsManager: config.formElementsManager, + activeTabValueExpression: this.getActiveTabVE(), + }), + }), + ], + items: [ + /* elements will be added dynamically*/ + ], + + }), config))()); + } + + onPageUpdate(): void { + let activeTab = this.getActiveTabVE().getValue(); + if (activeTab) { + this.setActiveTab(activeTab); + } else { + this.setActiveTab(0); + } + } +} + +export default PagesWrapperContainer; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/plugins/ShowFormIssuesPlugin.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/plugins/ShowFormIssuesPlugin.ts index bf2d2ba1..772a9106 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/plugins/ShowFormIssuesPlugin.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/plugins/ShowFormIssuesPlugin.ts @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import { bind } from "@jangaroo/runtime"; import Config from "@jangaroo/runtime/Config"; import ConfigUtils from "@jangaroo/runtime/ConfigUtils"; diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/studioform/FormEditorForm.ts b/apps/studio-client/apps/main/form-editor-studio-plugin/src/studioform/FormEditorForm.ts index 3b6820bd..5427ddd3 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/studioform/FormEditorForm.ts +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/studioform/FormEditorForm.ts @@ -1,29 +1,60 @@ +/* + * Copyright 2018 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import BlueprintTabs_properties from "@coremedia-blueprint/studio-client.main.blueprint-forms/BlueprintTabs_properties"; -import DetailsDocumentForm from "@coremedia-blueprint/studio-client.main.blueprint-forms/forms/containers/DetailsDocumentForm"; -import ExternallyVisibleDateForm from "@coremedia-blueprint/studio-client.main.blueprint-forms/forms/containers/ExternallyVisibleDateForm"; -import LinkedSettingsForm from "@coremedia-blueprint/studio-client.main.blueprint-forms/forms/containers/LinkedSettingsForm"; -import LocalSettingsForm from "@coremedia-blueprint/studio-client.main.blueprint-forms/forms/containers/LocalSettingsForm"; -import MediaDocumentForm from "@coremedia-blueprint/studio-client.main.blueprint-forms/forms/containers/MediaDocumentForm"; -import MultiLanguageDocumentForm from "@coremedia-blueprint/studio-client.main.blueprint-forms/forms/containers/MultiLanguageDocumentForm"; -import RelatedDocumentForm from "@coremedia-blueprint/studio-client.main.blueprint-forms/forms/containers/RelatedDocumentForm"; +import DetailsDocumentForm + from "@coremedia-blueprint/studio-client.main.blueprint-forms/forms/containers/DetailsDocumentForm"; +import ExternallyVisibleDateForm + from "@coremedia-blueprint/studio-client.main.blueprint-forms/forms/containers/ExternallyVisibleDateForm"; +import LinkedSettingsForm + from "@coremedia-blueprint/studio-client.main.blueprint-forms/forms/containers/LinkedSettingsForm"; +import LocalSettingsForm + from "@coremedia-blueprint/studio-client.main.blueprint-forms/forms/containers/LocalSettingsForm"; +import MediaDocumentForm + from "@coremedia-blueprint/studio-client.main.blueprint-forms/forms/containers/MediaDocumentForm"; +import MultiLanguageDocumentForm + from "@coremedia-blueprint/studio-client.main.blueprint-forms/forms/containers/MultiLanguageDocumentForm"; +import RelatedDocumentForm + from "@coremedia-blueprint/studio-client.main.blueprint-forms/forms/containers/RelatedDocumentForm"; import SearchableForm from "@coremedia-blueprint/studio-client.main.blueprint-forms/forms/containers/SearchableForm"; -import TeaserDocumentForm from "@coremedia-blueprint/studio-client.main.blueprint-forms/forms/containers/TeaserDocumentForm"; -import ValidityDocumentForm from "@coremedia-blueprint/studio-client.main.blueprint-forms/forms/containers/ValidityDocumentForm"; -import ViewTypeSelectorForm from "@coremedia-blueprint/studio-client.main.blueprint-forms/forms/containers/ViewTypeSelectorForm"; -import MetaDataDocumentForm from "@coremedia-blueprint/studio-client.main.blueprint-forms/forms/media/MetaDataDocumentForm"; +import TeaserDocumentForm + from "@coremedia-blueprint/studio-client.main.blueprint-forms/forms/containers/TeaserDocumentForm"; +import ValidityDocumentForm + from "@coremedia-blueprint/studio-client.main.blueprint-forms/forms/containers/ValidityDocumentForm"; +import ViewTypeSelectorForm + from "@coremedia-blueprint/studio-client.main.blueprint-forms/forms/containers/ViewTypeSelectorForm"; +import MetaDataDocumentForm + from "@coremedia-blueprint/studio-client.main.blueprint-forms/forms/media/MetaDataDocumentForm"; import SvgIconUtil from "@coremedia/studio-client.base-models/util/SvgIconUtil"; import LocalComboBox from "@coremedia/studio-client.ext.ui-components/components/LocalComboBox"; import BindPropertyPlugin from "@coremedia/studio-client.ext.ui-components/plugins/BindPropertyPlugin"; import DocumentForm from "@coremedia/studio-client.main.editor-components/sdk/premular/DocumentForm"; import DocumentInfo from "@coremedia/studio-client.main.editor-components/sdk/premular/DocumentInfo"; -import DocumentMetaDataFormDispatcher from "@coremedia/studio-client.main.editor-components/sdk/premular/DocumentMetaDataFormDispatcher"; +import DocumentMetaDataFormDispatcher + from "@coremedia/studio-client.main.editor-components/sdk/premular/DocumentMetaDataFormDispatcher"; import DocumentTabPanel from "@coremedia/studio-client.main.editor-components/sdk/premular/DocumentTabPanel"; import PropertyFieldGroup from "@coremedia/studio-client.main.editor-components/sdk/premular/PropertyFieldGroup"; import ReferrerListPanel from "@coremedia/studio-client.main.editor-components/sdk/premular/ReferrerListPanel"; import VersionHistory from "@coremedia/studio-client.main.editor-components/sdk/premular/VersionHistory"; -import BooleanPropertyField from "@coremedia/studio-client.main.editor-components/sdk/premular/fields/BooleanPropertyField"; -import StringPropertyField from "@coremedia/studio-client.main.editor-components/sdk/premular/fields/StringPropertyField"; -import StructPropertyField from "@coremedia/studio-client.main.editor-components/sdk/premular/fields/struct/StructPropertyField"; +import BooleanPropertyField + from "@coremedia/studio-client.main.editor-components/sdk/premular/fields/BooleanPropertyField"; +import StringPropertyField + from "@coremedia/studio-client.main.editor-components/sdk/premular/fields/StringPropertyField"; +import StructPropertyField + from "@coremedia/studio-client.main.editor-components/sdk/premular/fields/struct/StructPropertyField"; import JsonStore from "@jangaroo/ext-ts/data/JsonStore"; import Config from "@jangaroo/runtime/Config"; import ConfigUtils from "@jangaroo/runtime/ConfigUtils"; @@ -45,6 +76,21 @@ import InputCity from "../icons/input-city-zip.svg"; import InputFax from "../icons/input-fax.svg"; import InputPhone from "../icons/input-phone.svg"; import InputStreet from "../icons/input-street-nr.svg"; +import HiddenFieldEditor from "../elements/HiddenFieldEditor"; +import IbanFieldEditor from "../elements/IbanFieldEditor"; +import FormsStudioPlugin from "../FormsStudioPlugin"; +import Content from "@coremedia/studio-client.cap-rest-client/content/Content"; +import ContentPropertyNames from "@coremedia/studio-client.cap-rest-client/content/ContentPropertyNames"; +import IconButton from "@coremedia/studio-client.ext.ui-components/components/IconButton"; +import {bind} from "@jangaroo/runtime"; +import CoreIcons_properties from "@coremedia/studio-client.core-icons/CoreIcons_properties"; +import Container from "@jangaroo/ext-ts/container/Container"; +import HBoxLayout from "@jangaroo/ext-ts/layout/container/HBox"; +import BindVisibilityPlugin from "@coremedia/studio-client.ext.ui-components/plugins/BindVisibilityPlugin"; +import DisplayField from "@jangaroo/ext-ts/form/field/Display"; +import DisplayFieldSkin from "@coremedia/studio-client.ext.ui-components/skins/DisplayFieldSkin"; +import MessageBoxUtil from "@coremedia/studio-client.ext.ui-components/messagebox/MessageBoxUtil"; +import FormUtils from "../FormUtils"; interface FormEditorFormConfig extends Config { } @@ -65,24 +111,53 @@ class FormEditorForm extends DocumentTabPanel { }, ]; + activatePageableForms(): void { + let self = this.bindTo; + this.bindTo.loadValue(function (content: Content): void { + MessageBoxUtil.showConfirmation(FormEditor_properties.FormEditor_pages_mode_switch_title, + FormEditor_properties.FormEditor_pages_mode_switch_text_multi, "Ok", buttonId => { + if (buttonId === "ok") { + FormUtils.migrateToMultiPageForm(content, self); + } + }); + }); + } + + deActivatePageableForms(): void { + + let self = this.bindTo; + this.bindTo.loadValue(function (content: Content): void { + MessageBoxUtil.showConfirmation(FormEditor_properties.FormEditor_pages_mode_switch_title, + FormEditor_properties.FormEditor_pages_mode_switch_text_single, "Ok", buttonId => { + if (buttonId === "ok") { + FormUtils.migrateToSinglePageForm(content, self); + } + }); + }); + } + + showActivateButton(setting: number): boolean { + return !setting || setting == 0; + } + constructor(config: Config = null) { - super(ConfigUtils.apply(Config(FormEditorForm, { + super((() => ConfigUtils.apply(Config(FormEditorForm, { items: [ Config(DocumentForm, { title: FormEditor_properties.FormEditor_tab_content_title, items: [ - Config(DetailsDocumentForm, { bindTo: config.bindTo }), + Config(DetailsDocumentForm, {bindTo: config.bindTo}), Config(TeaserDocumentForm, { bindTo: config.bindTo, collapsed: true, }), - Config(MediaDocumentForm, { bindTo: config.bindTo }), - Config(RelatedDocumentForm, { bindTo: config.bindTo }), - Config(ViewTypeSelectorForm, { bindTo: config.bindTo }), - Config(ExternallyVisibleDateForm, { bindTo: config.bindTo }), - Config(ValidityDocumentForm, { bindTo: config.bindTo }), + Config(MediaDocumentForm, {bindTo: config.bindTo}), + Config(RelatedDocumentForm, {bindTo: config.bindTo}), + Config(ViewTypeSelectorForm, {bindTo: config.bindTo}), + Config(ExternallyVisibleDateForm, {bindTo: config.bindTo}), + Config(ValidityDocumentForm, {bindTo: config.bindTo}), ], }), Config(DocumentForm, { @@ -94,7 +169,57 @@ class FormEditorForm extends DocumentTabPanel { collapsed: false, itemId: "spamProtectionGroup", items: [ - Config(BooleanPropertyField, { propertyName: "spamProtectionEnabled" }), + Config(BooleanPropertyField, {propertyName: "spamProtectionEnabled"}), + ], + }), + Config(PropertyFieldGroup, { + title: FormContentTypes_properties.FormEditor_pageableFormEnabled_group_text, + collapsed: false, + itemId: "pageableFormGroup", + items: [ + Config(Container, { + layout: Config(HBoxLayout), + items: [ + Config(IconButton, { + iconCls: CoreIcons_properties.type_object, + tooltip: FormEditor_properties.FormEditor_pages_mode_single, + handler: bind(this, this.deActivatePageableForms), + }), + Config(DisplayField, { + value: FormEditor_properties.FormEditor_pages_mode_single, + ui: DisplayFieldSkin.ITALIC.getSkin(), + }), + ], + ...ConfigUtils.append({ + plugins: [ + Config(BindVisibilityPlugin, { + bindTo: config.bindTo.extendBy(ContentPropertyNames.PROPERTIES, FormsStudioPlugin.PAGEABLE_ENABLED), + }), + ] + }) + }), + Config(Container, { + layout: Config(HBoxLayout), + items: [ + Config(IconButton, { + iconCls: CoreIcons_properties.copy, + tooltip: FormEditor_properties.FormEditor_pages_mode_multi, + handler: bind(this, this.activatePageableForms), + }), + Config(DisplayField, { + value: FormEditor_properties.FormEditor_pages_mode_multi, + ui: DisplayFieldSkin.ITALIC.getSkin(), + }), + ], + ...ConfigUtils.append({ + plugins: [ + Config(BindVisibilityPlugin, { + bindTo: config.bindTo.extendBy(ContentPropertyNames.PROPERTIES, FormsStudioPlugin.PAGEABLE_ENABLED), + transformer: this.showActivateButton + }), + ] + }) + }), ], }), Config(PropertyFieldGroup, { @@ -122,7 +247,7 @@ class FormEditorForm extends DocumentTabPanel { data: FormEditorForm.#FORM_ACTIONS, }), }), - Config(StringPropertyField, { propertyName: "adminMails" }), + Config(StringPropertyField, {propertyName: "adminMails"}), ], }), @@ -131,7 +256,7 @@ class FormEditorForm extends DocumentTabPanel { Config(FormEditorDocumentForm, { bindTo: config.bindTo, forceReadOnlyValueExpression: config.forceReadOnlyValueExpression, - structPropertyName: "formData", + structPropertyName: FormsStudioPlugin.FORM_ELEMENTS_STRUCT_PROPERTY, formElements: [ Config(NumberFieldEditor), Config(TextAreaEditor), @@ -167,9 +292,11 @@ class FormEditorForm extends DocumentTabPanel { Config(CheckBoxesEditor), Config(RadioButtonsEditor), Config(DateFieldEditor), + Config(IbanFieldEditor), + Config(HiddenFieldEditor), ], }), - Config(MultiLanguageDocumentForm, { bindTo: config.bindTo }), + Config(MultiLanguageDocumentForm, {bindTo: config.bindTo}), Config(MetaDataDocumentForm), Config(DocumentForm, { title: BlueprintTabs_properties.Tab_system_title, @@ -179,9 +306,9 @@ class FormEditorForm extends DocumentTabPanel { Config(DocumentInfo), Config(VersionHistory), Config(ReferrerListPanel), - Config(SearchableForm, { collapsed: true }), - Config(LinkedSettingsForm, { collapsed: true }), - Config(LocalSettingsForm, { collapsed: true }), + Config(SearchableForm, {collapsed: true}), + Config(LinkedSettingsForm, {collapsed: true}), + Config(LocalSettingsForm, {collapsed: true}), Config(PropertyFieldGroup, { title: FormContentTypes_properties.FormEditor_formData_text, collapsed: true, @@ -189,7 +316,7 @@ class FormEditorForm extends DocumentTabPanel { items: [ Config(StructPropertyField, { - propertyName: "formData", + propertyName: FormsStudioPlugin.FORM_ELEMENTS_STRUCT_PROPERTY, hideLabel: true, itemId: "formData", }), @@ -202,7 +329,7 @@ class FormEditorForm extends DocumentTabPanel { }), ], - }), config)); + }), config))()); } } diff --git a/apps/studio-client/apps/main/form-editor-studio-plugin/src/tsconfig.json b/apps/studio-client/apps/main/form-editor-studio-plugin/src/tsconfig.json index 2db15d83..4828f693 100644 --- a/apps/studio-client/apps/main/form-editor-studio-plugin/src/tsconfig.json +++ b/apps/studio-client/apps/main/form-editor-studio-plugin/src/tsconfig.json @@ -5,188 +5,7 @@ "compilerOptions": { "rootDir": ".", "outDir": "../dist/src", - "paths": { - "@coremedia-blueprint/studio-client.blueprint-doctypes/*": [ - "../../../../../../../../../apps/studio-client/shared/js/blueprint-doctypes/src/*" - ], - "@coremedia-blueprint/studio-client.form-editor/*": [ - "../../../../shared/js/form-editor/src/*" - ], - "@coremedia-blueprint/studio-client.main.blueprint-forms/*": [ - "../../../../../../../../../apps/studio-client/apps/main/blueprint-forms/src/*" - ], - "@coremedia/studio-client.app-context-models/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.app-context-models@2201.2.0/node_modules/@coremedia/studio-client.app-context-models/src/*" - ], - "@coremedia/studio-client.base-models/*": [ - "../node_modules/@coremedia/studio-client.base-models/src/*" - ], - "@coremedia/studio-client.cap-base-models/*": [ - "../node_modules/@coremedia/studio-client.cap-base-models/src/*" - ], - "@coremedia/studio-client.cap-base-services-api/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.cap-base-services-api@2201.2.0/node_modules/@coremedia/studio-client.cap-base-services-api/src/*" - ], - "@coremedia/studio-client.cap-base-services-toolkit/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.cap-base-services-toolkit@2201.2.0/node_modules/@coremedia/studio-client.cap-base-services-toolkit/src/*" - ], - "@coremedia/studio-client.cap-rest-client/*": [ - "../node_modules/@coremedia/studio-client.cap-rest-client/src/*" - ], - "@coremedia/studio-client.cap-rest-client-impl/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.cap-rest-client-impl@2201.2.0/node_modules/@coremedia/studio-client.cap-rest-client-impl/src/*" - ], - "@coremedia/studio-client.ckeditor-constants/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.ckeditor-constants@2201.2.0/node_modules/@coremedia/studio-client.ckeditor-constants/src/*" - ], - "@coremedia/studio-client.ckeditor-factory/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.ckeditor-factory@2201.2.0/node_modules/@coremedia/studio-client.ckeditor-factory/src/*" - ], - "@coremedia/studio-client.client-core/*": [ - "../node_modules/@coremedia/studio-client.client-core/src/*" - ], - "@coremedia/studio-client.client-core-impl/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.client-core-impl@2201.2.0/node_modules/@coremedia/studio-client.client-core-impl/src/*" - ], - "@coremedia/studio-client.collaboration-icons/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.collaboration-icons@2201.2.0/node_modules/@coremedia/studio-client.collaboration-icons/src/*" - ], - "@coremedia/studio-client.content-link-list-models/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.content-link-list-models@2201.2.0/node_modules/@coremedia/studio-client.content-link-list-models/src/*" - ], - "@coremedia/studio-client.core-icons/*": [ - "../node_modules/@coremedia/studio-client.core-icons/src/*" - ], - "@coremedia/studio-client.embed-app-services-api/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.embed-app-services-api@2201.2.0/node_modules/@coremedia/studio-client.embed-app-services-api/src/*" - ], - "@coremedia/studio-client.ext.base-components/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.ext.base-components@2201.2.0/node_modules/@coremedia/studio-client.ext.base-components/src/*" - ], - "@coremedia/studio-client.ext.cap-base-components/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.ext.cap-base-components@2201.2.0/node_modules/@coremedia/studio-client.ext.cap-base-components/src/*" - ], - "@coremedia/studio-client.ext.content-link-list-components/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.ext.content-link-list-components@2201.2.0/node_modules/@coremedia/studio-client.ext.content-link-list-components/src/*" - ], - "@coremedia/studio-client.ext.errors-validation-components/*": [ - "../node_modules/@coremedia/studio-client.ext.errors-validation-components/src/*" - ], - "@coremedia/studio-client.ext.form-services-toolkit/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.ext.form-services-toolkit@2201.2.0/node_modules/@coremedia/studio-client.ext.form-services-toolkit/src/*" - ], - "@coremedia/studio-client.ext.frame-components/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.ext.frame-components@2201.2.0/node_modules/@coremedia/studio-client.ext.frame-components/src/*" - ], - "@coremedia/studio-client.ext.interaction-components/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.ext.interaction-components@2201.2.0/node_modules/@coremedia/studio-client.ext.interaction-components/src/*" - ], - "@coremedia/studio-client.ext.library-services-toolkit/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.ext.library-services-toolkit@2201.2.0/node_modules/@coremedia/studio-client.ext.library-services-toolkit/src/*" - ], - "@coremedia/studio-client.ext.link-list-components/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.ext.link-list-components@2201.2.0/node_modules/@coremedia/studio-client.ext.link-list-components/src/*" - ], - "@coremedia/studio-client.ext.logger-components/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.ext.logger-components@2201.2.0/node_modules/@coremedia/studio-client.ext.logger-components/src/*" - ], - "@coremedia/studio-client.ext.lottie-components/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.ext.lottie-components@2201.2.0/node_modules/@coremedia/studio-client.ext.lottie-components/src/*" - ], - "@coremedia/studio-client.ext.multi-site-components/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.ext.multi-site-components@2201.2.0/node_modules/@coremedia/studio-client.ext.multi-site-components/src/*" - ], - "@coremedia/studio-client.ext.richtext-components-toolkit/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.ext.richtext-components-toolkit@2201.2.0/node_modules/@coremedia/studio-client.ext.richtext-components-toolkit/src/*" - ], - "@coremedia/studio-client.ext.split-main-view-components/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.ext.split-main-view-components@2201.2.0/node_modules/@coremedia/studio-client.ext.split-main-view-components/src/*" - ], - "@coremedia/studio-client.ext.startup-components/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.ext.startup-components@2201.2.0/node_modules/@coremedia/studio-client.ext.startup-components/src/*" - ], - "@coremedia/studio-client.ext.startup-plugins/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.ext.startup-plugins@2201.2.0/node_modules/@coremedia/studio-client.ext.startup-plugins/src/*" - ], - "@coremedia/studio-client.ext.toast-components/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.ext.toast-components@2201.2.0/node_modules/@coremedia/studio-client.ext.toast-components/src/*" - ], - "@coremedia/studio-client.ext.ui-components/*": [ - "../node_modules/@coremedia/studio-client.ext.ui-components/src/*" - ], - "@coremedia/studio-client.ext.workflow-components/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.ext.workflow-components@2201.2.0/node_modules/@coremedia/studio-client.ext.workflow-components/src/*" - ], - "@coremedia/studio-client.ext.workflow-services-toolkit/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.ext.workflow-services-toolkit@2201.2.0/node_modules/@coremedia/studio-client.ext.workflow-services-toolkit/src/*" - ], - "@coremedia/studio-client.form-models/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.form-models@2201.2.0/node_modules/@coremedia/studio-client.form-models/src/*" - ], - "@coremedia/studio-client.form-services-api/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.form-services-api@2201.2.0/node_modules/@coremedia/studio-client.form-services-api/src/*" - ], - "@coremedia/studio-client.interaction-services-api/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.interaction-services-api@2201.2.0/node_modules/@coremedia/studio-client.interaction-services-api/src/*" - ], - "@coremedia/studio-client.interaction-services-impl/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.interaction-services-impl@2201.2.0/node_modules/@coremedia/studio-client.interaction-services-impl/src/*" - ], - "@coremedia/studio-client.kinetic-js/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.kinetic-js@2201.2.0/node_modules/@coremedia/studio-client.kinetic-js/src/*" - ], - "@coremedia/studio-client.library-services-api/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.library-services-api@2201.2.0/node_modules/@coremedia/studio-client.library-services-api/src/*" - ], - "@coremedia/studio-client.link-list-models/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.link-list-models@2201.2.0/node_modules/@coremedia/studio-client.link-list-models/src/*" - ], - "@coremedia/studio-client.main.bpbase-pagegrid-studio-plugin/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.main.bpbase-pagegrid-studio-plugin@2201.2.0/node_modules/@coremedia/studio-client.main.bpbase-pagegrid-studio-plugin/src/*" - ], - "@coremedia/studio-client.main.bpbase-studio-components/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.main.bpbase-studio-components@2201.2.0/node_modules/@coremedia/studio-client.main.bpbase-studio-components/src/*" - ], - "@coremedia/studio-client.main.bpbase-studio-dynamic-query-list/*": [ - "../node_modules/@coremedia/studio-client.main.bpbase-studio-dynamic-query-list/src/*" - ], - "@coremedia/studio-client.main.ckeditor4-components/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.main.ckeditor4-components@2201.2.0/node_modules/@coremedia/studio-client.main.ckeditor4-components/src/*" - ], - "@coremedia/studio-client.main.editor-components/*": [ - "../node_modules/@coremedia/studio-client.main.editor-components/src/*" - ], - "@coremedia/studio-client.main.image-editor-components/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.main.image-editor-components@2201.2.0/node_modules/@coremedia/studio-client.main.image-editor-components/src/*" - ], - "@coremedia/studio-client.main.image-map-editor-components/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.main.image-map-editor-components@2201.2.0/node_modules/@coremedia/studio-client.main.image-map-editor-components/src/*" - ], - "@coremedia/studio-client.multi-site-models/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.multi-site-models@2201.2.0/node_modules/@coremedia/studio-client.multi-site-models/src/*" - ], - "@coremedia/studio-client.workflow-issues-services-api/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.workflow-issues-services-api@2201.2.0/node_modules/@coremedia/studio-client.workflow-issues-services-api/src/*" - ], - "@coremedia/studio-client.workflow-models/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.workflow-models@2201.2.0/node_modules/@coremedia/studio-client.workflow-models/src/*" - ], - "@coremedia/studio-client.workflow-plugin-models/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.workflow-plugin-models@2201.2.0/node_modules/@coremedia/studio-client.workflow-plugin-models/src/*" - ], - "@coremedia/studio-client.workflow-services-api/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.workflow-services-api@2201.2.0/node_modules/@coremedia/studio-client.workflow-services-api/src/*" - ], - "@jangaroo/ext-ts/*": [ - "../node_modules/@jangaroo/ext-ts/src/*" - ], - "@jangaroo/jangaroo-net/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@jangaroo+jangaroo-net@1.1.1/node_modules/@jangaroo/jangaroo-net/src/*" - ], - "@jangaroo/runtime/*": [ - "../node_modules/@jangaroo/runtime/src/*" - ] - }, + "moduleResolution": "nodenext", "types": [ "@coremedia/studio-client.client-core", "@coremedia/studio-client.main.editor-components", diff --git a/apps/studio-client/apps/workflow/form-editor-workflow-plugin/package.json b/apps/studio-client/apps/workflow/form-editor-workflow-plugin/package.json index d6c390c5..fd8e0d36 100644 --- a/apps/studio-client/apps/workflow/form-editor-workflow-plugin/package.json +++ b/apps/studio-client/apps/workflow/form-editor-workflow-plugin/package.json @@ -6,11 +6,11 @@ "@coremedia-blueprint/studio-client.form-editor": "1.0.0-SNAPSHOT" }, "devDependencies": { - "@jangaroo/build": "^1.1.1", - "@jangaroo/core": "^1.1.1", - "@jangaroo/eslint-config": "^1.1.1", - "@jangaroo/publish": "^1.1.1", - "eslint": "^7.27.0", + "@jangaroo/build": "^1.4.2", + "@jangaroo/core": "^1.4.2", + "@jangaroo/eslint-config": "^1.4.2", + "@jangaroo/publish": "^1.4.2", + "eslint": "^7.32.0", "rimraf": "^3.0.2" }, "scripts": { diff --git a/apps/studio-client/package.json b/apps/studio-client/package.json index ebe7bce0..b10084a3 100644 --- a/apps/studio-client/package.json +++ b/apps/studio-client/package.json @@ -3,8 +3,8 @@ "version": "1.0.0-SNAPSHOT", "private": true, "engines": { - "node": ">=16", - "pnpm": ">=6.14.6" + "node": "18", + "pnpm": "^8.1" }, "devDependencies": { "@coremedia/set-version": "^1.1.1" diff --git a/apps/studio-client/shared/js/form-editor/package.json b/apps/studio-client/shared/js/form-editor/package.json index feb90c7c..6efcea49 100644 --- a/apps/studio-client/shared/js/form-editor/package.json +++ b/apps/studio-client/shared/js/form-editor/package.json @@ -2,15 +2,15 @@ "name": "@coremedia-blueprint/studio-client.form-editor", "version": "1.0.0-SNAPSHOT", "dependencies": { - "@coremedia/studio-client.cap-base-models": "2201.2.0", - "@jangaroo/runtime": "^1.1.1" + "@coremedia/studio-client.cap-base-models": "2304.1.0", + "@jangaroo/runtime": "^1.4.2" }, "devDependencies": { - "@jangaroo/build": "^1.1.1", - "@jangaroo/core": "^1.1.1", - "@jangaroo/eslint-config": "^1.1.1", - "@jangaroo/publish": "^1.1.1", - "eslint": "^7.27.0", + "@jangaroo/build": "^1.4.2", + "@jangaroo/core": "^1.4.2", + "@jangaroo/eslint-config": "^1.4.2", + "@jangaroo/publish": "^1.4.2", + "eslint": "^7.32.0", "rimraf": "^3.0.2" }, "scripts": { diff --git a/apps/studio-client/shared/js/form-editor/src/tsconfig.json b/apps/studio-client/shared/js/form-editor/src/tsconfig.json index b66335b8..2ec7410b 100644 --- a/apps/studio-client/shared/js/form-editor/src/tsconfig.json +++ b/apps/studio-client/shared/js/form-editor/src/tsconfig.json @@ -5,37 +5,6 @@ "compilerOptions": { "rootDir": ".", "outDir": "../dist/src", - "paths": { - "@coremedia/studio-client.base-models/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.base-models@2201.2.0/node_modules/@coremedia/studio-client.base-models/src/*" - ], - "@coremedia/studio-client.cap-base-models/*": [ - "../node_modules/@coremedia/studio-client.cap-base-models/src/*" - ], - "@coremedia/studio-client.cap-base-services-api/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.cap-base-services-api@2201.2.0/node_modules/@coremedia/studio-client.cap-base-services-api/src/*" - ], - "@coremedia/studio-client.cap-rest-client/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.cap-rest-client@2201.2.0/node_modules/@coremedia/studio-client.cap-rest-client/src/*" - ], - "@coremedia/studio-client.cap-rest-client-impl/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.cap-rest-client-impl@2201.2.0/node_modules/@coremedia/studio-client.cap-rest-client-impl/src/*" - ], - "@coremedia/studio-client.client-core/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.client-core@2201.2.0/node_modules/@coremedia/studio-client.client-core/src/*" - ], - "@coremedia/studio-client.client-core-impl/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.client-core-impl@2201.2.0/node_modules/@coremedia/studio-client.client-core-impl/src/*" - ], - "@coremedia/studio-client.core-icons/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@coremedia+studio-client.core-icons@2201.2.0/node_modules/@coremedia/studio-client.core-icons/src/*" - ], - "@jangaroo/jangaroo-net/*": [ - "../../../../../../../../../apps/studio-client/node_modules/.pnpm/@jangaroo+jangaroo-net@1.1.1/node_modules/@jangaroo/jangaroo-net/src/*" - ], - "@jangaroo/runtime/*": [ - "../node_modules/@jangaroo/runtime/src/*" - ] - } + "moduleResolution": "nodenext" } } diff --git a/form-editor-cae/pom.xml b/form-editor-cae/pom.xml index 772bc38f..46c5182e 100644 --- a/form-editor-cae/pom.xml +++ b/form-editor-cae/pom.xml @@ -65,28 +65,26 @@ com.coremedia.cms cae-linkservices - - com.coremedia.cms - coremedia-spring - com.coremedia.cms cap-unified-api + + provided com.coremedia.cms coremedia-cache - - - org.springframework.boot - spring-boot-autoconfigure + com.coremedia.cms + cae-viewservices - org.springframework.boot - spring-boot + com.coremedia.cms + coremedia-xml + + org.springframework spring-beans @@ -158,6 +156,16 @@ spring-test test + + org.springframework.boot + spring-boot-autoconfigure + test + + + org.springframework.boot + spring-boot + test + junit junit @@ -195,6 +203,11 @@ cap-client-xml test + + com.coremedia.cms + coremedia-spring + test + ${project.groupId} image-transformation @@ -210,19 +223,31 @@ org.skyscreamer jsonassert test + 1.2.1 commons-io commons-io test + + com.coremedia.cms + cap-multisite + test + + + ${project.groupId} + content-services + ${project.version} + test + commons-fileupload commons-fileupload - 1.4 + 1.5 diff --git a/form-editor-cae/src/main/java/com/tallence/formeditor/cae/handler/FormConfigController.java b/form-editor-cae/src/main/java/com/tallence/formeditor/cae/handler/FormConfigController.java index a1a1f523..378e8250 100644 --- a/form-editor-cae/src/main/java/com/tallence/formeditor/cae/handler/FormConfigController.java +++ b/form-editor-cae/src/main/java/com/tallence/formeditor/cae/handler/FormConfigController.java @@ -23,19 +23,26 @@ import com.coremedia.blueprint.common.navigation.Navigation; import com.coremedia.blueprint.common.services.context.CurrentContextService; import com.coremedia.cache.Cache; +import com.coremedia.objectserver.view.View; +import com.coremedia.objectserver.view.XmlMarkupView; import com.coremedia.objectserver.web.links.Link; import com.coremedia.objectserver.web.links.LinkFormatter; +import com.coremedia.xml.Markup; +import com.coremedia.xml.MarkupFactory; import com.tallence.formeditor.cae.FormFreemarkerFacade; -import com.tallence.formeditor.elements.FormElement; import com.tallence.formeditor.cae.model.FormEditorConfig; import com.tallence.formeditor.cae.serializer.FormConfigCacheKey; import com.tallence.formeditor.cae.serializer.FormElementSerializerFactory; import com.tallence.formeditor.contentbeans.FormEditor; -import com.tallence.formeditor.parser.CurrentFormSupplier; +import com.tallence.formeditor.elements.FormElement; +import com.tallence.formeditor.elements.PageElement; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.server.ResponseStatusException; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.util.UriComponents; @@ -43,7 +50,9 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.io.StringWriter; import java.util.List; +import java.util.stream.Collectors; import static com.coremedia.objectserver.web.HandlerHelper.MODEL_ROOT; @@ -67,18 +76,21 @@ public class FormConfigController { private final ResourceBundleInterceptor pageResourceBundlesInterceptor; private final Cache cache; private final List> formElementSerializerFactories; + private final View richtextMarkupView; public FormConfigController(CurrentContextService currentContextService, FormFreemarkerFacade formFreemarkerFacade, LinkFormatter linkFormatter, RequestMessageSource messageSource, ResourceBundleInterceptor pageResourceBundlesInterceptor, + View richtextMarkupView, Cache cache, List> formElementSerializerFactories) { this.currentContextService = currentContextService; this.formFreemarkerFacade = formFreemarkerFacade; this.linkFormatter = linkFormatter; this.messageSource = messageSource; this.pageResourceBundlesInterceptor = pageResourceBundlesInterceptor; + this.richtextMarkupView = richtextMarkupView; this.cache = cache; this.formElementSerializerFactories = formElementSerializerFactories; } @@ -106,7 +118,6 @@ public String getFormConfig(@PathVariable CMChannel currentContext, Navigation navigation = currentContext.getRootNavigation(); request.setAttribute(NavigationLinkSupport.ATTR_NAME_CMNAVIGATION, navigation); - CurrentFormSupplier.setCurrentForm(editor.getContent()); List> formElements = formFreemarkerFacade.parseFormElements(editor); if (formElements.isEmpty()) { @@ -121,7 +132,22 @@ public String getFormConfig(@PathVariable CMChannel currentContext, //prepare form config FormEditorConfig formEditorConfig = new FormEditorConfig(); formEditorConfig.setFormActionUrl(linkFormatter.formatLink(editor, FormController.FORM_EDITOR_SUBMIT_VIEW, request, response, false)); - formEditorConfig.setFormElements(formElements); + + if (editor.isPageableFormEnabled()) { + var pages = formElements.stream() + .map(f -> (PageElement) f) + .map(p -> new FormEditorConfig.FormPage(p.getId(), + transformMarkup(p.getPageDescription(), request, response), + p.getName(), + p.getPageType(), + p.getSubElements())) + .collect(Collectors.toList()); + formEditorConfig.setPages(pages); + } else { + //Create a virtual page, to produce the same json structure + formEditorConfig.setPage(new FormEditorConfig.FormPage(formElements)); + } + return this.cache.get(new FormConfigCacheKey( editor, request, response, @@ -131,4 +157,17 @@ public String getFormConfig(@PathVariable CMChannel currentContext, } + private String transformMarkup(Markup pageDescription, HttpServletRequest request, HttpServletResponse response) { + if (pageDescription == null) { + return null; + } + + StringWriter out = new StringWriter(); + var serializer = MarkupFactory.newSerializer(out); + ((XmlMarkupView) richtextMarkupView).render(pageDescription, null, serializer, request, response); + + + return out.toString(); + } + } diff --git a/form-editor-cae/src/main/java/com/tallence/formeditor/cae/handler/FormController.java b/form-editor-cae/src/main/java/com/tallence/formeditor/cae/handler/FormController.java index b6af4409..87bb606f 100644 --- a/form-editor-cae/src/main/java/com/tallence/formeditor/cae/handler/FormController.java +++ b/form-editor-cae/src/main/java/com/tallence/formeditor/cae/handler/FormController.java @@ -32,7 +32,6 @@ import com.tallence.formeditor.cae.model.FormSuccessResult; import com.tallence.formeditor.cae.model.FormValidationResult; import com.tallence.formeditor.cae.serializer.ValidationSerializationHelper; -import com.tallence.formeditor.parser.CurrentFormSupplier; import com.tallence.formeditor.validator.ValidationFieldError; import com.tallence.formeditor.contentbeans.FormEditor; import org.slf4j.Logger; @@ -130,9 +129,10 @@ public FormProcessingResult socialFormAction(@PathVariable(name = "currentContex modelAndView.addObject(MODEL_ROOT, navigation); pageResourceBundlesInterceptor.postHandle(request, response, null, modelAndView); request.setAttribute(NavigationLinkSupport.ATTR_NAME_CMNAVIGATION, navigation); - CurrentFormSupplier.setCurrentForm(target.getContent()); - List> formElements = formFreemarkerFacade.parseFormElements(target); + List> formElements = formFreemarkerFacade.parseFormElements(target) + .stream().flatMap(e -> e.flattenFormElements().stream()) + .collect(Collectors.toList()); if (formElements.isEmpty()) { return new FormProcessingResult( false, diff --git a/form-editor-cae/src/main/java/com/tallence/formeditor/cae/model/FormEditorConfig.java b/form-editor-cae/src/main/java/com/tallence/formeditor/cae/model/FormEditorConfig.java index a74b4837..3e6457d0 100644 --- a/form-editor-cae/src/main/java/com/tallence/formeditor/cae/model/FormEditorConfig.java +++ b/form-editor-cae/src/main/java/com/tallence/formeditor/cae/model/FormEditorConfig.java @@ -17,14 +17,16 @@ package com.tallence.formeditor.cae.model; import com.tallence.formeditor.elements.FormElement; +import com.tallence.formeditor.elements.PageElement; +import java.util.Collections; import java.util.List; public class FormEditorConfig { private String formActionUrl; - private List> formElements; + private List pages; public String getFormActionUrl() { return formActionUrl; @@ -34,13 +36,60 @@ public void setFormActionUrl(String formActionUrl) { this.formActionUrl = formActionUrl; } - public List> getFormElements() { - return formElements; + public void setPages(List pages) { + this.pages = pages; } - public void setFormElements(List> formElements) { - this.formElements = formElements; + public void setPage(FormPage page) { + this.pages = Collections.singletonList(page); } + public List getPages() { + return pages; + } + + public static class FormPage { + + private final String id; + private final String description; + private final String title; + private final PageElement.PageType pageType; + private final List> formElements; + + public FormPage(List> formElements) { + this.id = null; + this.description = null; + this.title = null; + this.pageType = PageElement.PageType.DEFAULT_PAGE; + this.formElements = formElements; + } + + public FormPage(String id, String description, String title, PageElement.PageType pageType, List> formElements) { + this.id = id; + this.description = description; + this.title = title; + this.pageType = pageType; + this.formElements = formElements; + } + public String getId() { + return id; + } + + public String getDescription() { + return description; + } + + public String getTitle() { + return title; + } + + public PageElement.PageType getPageType() { + return pageType; + } + + public List> getFormElements() { + return formElements; + } + } } diff --git a/form-editor-cae/src/main/java/com/tallence/formeditor/cae/serializer/HiddenFieldSerializerFactory.java b/form-editor-cae/src/main/java/com/tallence/formeditor/cae/serializer/HiddenFieldSerializerFactory.java new file mode 100644 index 00000000..7e6e8028 --- /dev/null +++ b/form-editor-cae/src/main/java/com/tallence/formeditor/cae/serializer/HiddenFieldSerializerFactory.java @@ -0,0 +1,56 @@ +/* + * Copyright 2022 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.tallence.formeditor.cae.serializer; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.tallence.formeditor.elements.HiddenField; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.function.BiFunction; + + +@Component +public class HiddenFieldSerializerFactory implements FormElementSerializerFactory { + + @Override + public HiddenFieldSerializer createInstance(BiFunction messageResolver, + HttpServletRequest request, HttpServletResponse response) { + return new HiddenFieldSerializer(messageResolver); + } + + /** + * Serializer for the {@link HiddenField} + */ + public static class HiddenFieldSerializer extends FormElementSerializerBase { + + public HiddenFieldSerializer(BiFunction messageResolver) { + super(HiddenField.class, messageResolver); + } + + @Override + public void serializeTypeSpecificFields(HiddenField field, JsonGenerator gen) throws IOException { + if (StringUtils.isNotEmpty(field.getValue())) { + gen.writeStringField("value", field.getValue()); + } + } + + } +} diff --git a/form-editor-cae/src/test/java/com/tallence/formeditor/cae/FormTestConfiguration.java b/form-editor-cae/src/test/java/com/tallence/formeditor/cae/FormTestConfiguration.java index 96c31878..f4ff3ab6 100644 --- a/form-editor-cae/src/test/java/com/tallence/formeditor/cae/FormTestConfiguration.java +++ b/form-editor-cae/src/test/java/com/tallence/formeditor/cae/FormTestConfiguration.java @@ -26,6 +26,7 @@ import com.coremedia.cap.test.xmlrepo.XmlUapiConfig; import com.coremedia.cms.delivery.configuration.DeliveryConfigurationProperties; import com.coremedia.objectserver.configuration.CaeConfigurationProperties; +import com.coremedia.objectserver.view.View; import com.coremedia.objectserver.web.config.CaeHandlerServicesConfiguration; import com.coremedia.objectserver.web.links.LinkFormatter; import com.coremedia.springframework.xml.ResourceAwareXmlBeanDefinitionReader; @@ -136,12 +137,14 @@ FormConfigController formConfigController(CurrentContextService currentContextSe LinkFormatter linkFormatter, RequestMessageSource messageSource, ResourceBundleInterceptor pageResourceBundlesInterceptor, + View richtextMarkupView, Cache cache, List> formElementSerializerFactories) { return new FormConfigController(currentContextService, formFreemarkerFacade, linkFormatter, messageSource, pageResourceBundlesInterceptor, + richtextMarkupView, cache, formElementSerializerFactories); } diff --git a/form-editor-cae/src/test/java/com/tallence/formeditor/cae/handler/FormConfigControllerTest.java b/form-editor-cae/src/test/java/com/tallence/formeditor/cae/handler/FormConfigControllerTest.java index c9aa8454..c8d6be60 100644 --- a/form-editor-cae/src/test/java/com/tallence/formeditor/cae/handler/FormConfigControllerTest.java +++ b/form-editor-cae/src/test/java/com/tallence/formeditor/cae/handler/FormConfigControllerTest.java @@ -68,6 +68,20 @@ public void testConfigJson() throws Exception { JSONAssert.assertEquals(expectedConfig, responseBody, JSONCompareMode.LENIENT); } + @Test + public void testPagedConfigJson() throws Exception { + URI CONFIG_URL = UriComponentsBuilder.fromUriString(FORM_EDITOR_CONFIG_URL).buildAndExpand("8", "20").toUri(); + String expectedConfig = IOUtils.toString(getClass().getResourceAsStream("/com/tallence/formeditor/cae/testdata/expectedConfig-6-20.json"), StandardCharsets.UTF_8); + + MvcResult result = mvc.perform(MockMvcRequestBuilders.get(CONFIG_URL)) + .andExpect(status().isOk()) + .andReturn(); + + String responseBody = result.getResponse().getContentAsString(); + + JSONAssert.assertEquals(expectedConfig, responseBody, JSONCompareMode.LENIENT); + } + @Test public void testEmptyConfigJson() throws Exception { URI CONFIG_URL = UriComponentsBuilder.fromUriString(FORM_EDITOR_CONFIG_URL).buildAndExpand("8", "6").toUri(); diff --git a/form-editor-cae/src/test/java/com/tallence/formeditor/cae/handler/FormControllerTest.java b/form-editor-cae/src/test/java/com/tallence/formeditor/cae/handler/FormControllerTest.java index 52971d66..982e561c 100644 --- a/form-editor-cae/src/test/java/com/tallence/formeditor/cae/handler/FormControllerTest.java +++ b/form-editor-cae/src/test/java/com/tallence/formeditor/cae/handler/FormControllerTest.java @@ -88,6 +88,7 @@ public class FormControllerTest { "DateField max: December 31, 1999
      " + "TextOnly: Das ist ein langer Text zur Erklärung des Formulars
      " + "UsersMail: " + MAIL_ADDRESS_TEST + "
      " + + "HiddenFieldName: HiddenValue
      " + "Data protection consent form: true
      "; @After @@ -111,6 +112,7 @@ public void testValidPost() throws Exception { .param("DateField_DateFieldMin", "2099-12-31T00:00:00.000Z") .param("DateField_DateFieldMax", "1999-12-31T00:00:00.000Z") .param("UsersMail_UsersMail", MAIL_ADDRESS_TEST) + .param("HiddenField_HiddenField", "HiddenValue") .param("ConsentFormCheckBox_ConsentFormCheckBox", "on") ) .andExpect(status().is2xxSuccessful()) @@ -169,6 +171,7 @@ public void testValidPostWithFile() throws Exception { .param("DateField_DateFieldMin", "2099-12-31T00:00:00.000Z") .param("DateField_DateFieldMax", "1999-12-31T00:00:00.000Z") .param("UsersMail_UsersMail", MAIL_ADDRESS_TEST) + .param("HiddenField_HiddenField", "HiddenValue") .param("ConsentFormCheckBox_ConsentFormCheckBox", "on") ) .andExpect(status().is2xxSuccessful()) @@ -256,6 +259,7 @@ public void testPostWithDependentFieldPositive() throws Exception { .param("DateField_DateFieldMin", "2099-12-31T00:00:00.000Z") .param("DateField_DateFieldMax", "1999-12-31T00:00:00.000Z") .param("UsersMail_UsersMail", MAIL_ADDRESS_TEST) + .param("HiddenField_HiddenField", "HiddenValue") .param("ConsentFormCheckBox_ConsentFormCheckBox", "on") ) .andExpect(status().is2xxSuccessful()) @@ -269,4 +273,20 @@ public void testPostWithDependentFieldPositive() throws Exception { assertEquals(MAIL_ADDRESS_TEST, mailAdapterMock.usersRecipient); } + @Test + public void testPostWithPagedElements() throws Exception { + mvc.perform(multipart(UriComponentsBuilder.fromUriString(FORM_EDITOR_SUBMIT_URL).buildAndExpand("8", "20").toUri()) + .param("TextArea_SubTextArea", "Message") + .param("HiddenField_HiddenField", "HiddenValue") + .param("NumberField_NumberField", "18") + ) + .andExpect(status().is2xxSuccessful()) + .andExpect(content().string(SUCCESS_RESPONSE)) + .andDo(MockMvcResultHandlers.print()); + + String withNewField = "SubTextArea: Message
      HiddenFieldName: HiddenValue
      Street and number:
      TextOnly: Das ist ein langer Text zur Erklärung des PageTab 2
      Alter: 18
      "; + + assertEquals(withNewField, mailAdapterMock.adminFormData); + } + } diff --git a/form-editor-cae/src/test/java/com/tallence/formeditor/cae/mocks/ResourceBundleFactoryMock.java b/form-editor-cae/src/test/java/com/tallence/formeditor/cae/mocks/ResourceBundleFactoryMock.java index f713e3ea..d363b906 100644 --- a/form-editor-cae/src/test/java/com/tallence/formeditor/cae/mocks/ResourceBundleFactoryMock.java +++ b/form-editor-cae/src/test/java/com/tallence/formeditor/cae/mocks/ResourceBundleFactoryMock.java @@ -1,8 +1,11 @@ package com.tallence.formeditor.cae.mocks; import com.coremedia.blueprint.cae.web.i18n.LinklistPageResourceBundleFactory; +import com.coremedia.blueprint.coderesources.ThemeService; import com.coremedia.blueprint.common.contentbeans.Page; import com.coremedia.blueprint.common.navigation.Navigation; +import com.coremedia.blueprint.localization.LocalizationService; +import com.coremedia.cap.multisite.SitesService; import com.coremedia.cap.user.User; import edu.umd.cs.findbugs.annotations.Nullable; @@ -12,6 +15,12 @@ public class ResourceBundleFactoryMock extends LinklistPageResourceBundleFactory { + public ResourceBundleFactoryMock(SitesService sitesService, LocalizationService localizationService, ThemeService themeService) { + setLocalizationService(localizationService); + setSitesService(sitesService); + setThemeService(themeService); + } + @Override public ResourceBundle resourceBundle(Page page, @Nullable User developer) { return resourceBundle(page.getNavigation(), developer); diff --git a/form-editor-cae/src/test/resources/com/tallence/formeditor/cae/testdata/expectedConfig-6-2.json b/form-editor-cae/src/test/resources/com/tallence/formeditor/cae/testdata/expectedConfig-6-2.json index f24d17fa..1581d262 100644 --- a/form-editor-cae/src/test/resources/com/tallence/formeditor/cae/testdata/expectedConfig-6-2.json +++ b/form-editor-cae/src/test/resources/com/tallence/formeditor/cae/testdata/expectedConfig-6-2.json @@ -1,374 +1,386 @@ { "formActionUrl": "/dynamic/forms/formEditorSubmit/8/2", - "formElements": [ + "pages": [ { - "id": "TextField", - "technicalName": "TextField_TextField", - "name": "TestName", - "hint": "Geben Sie etwas ein!", - "placeholder": "Platzhalter", - "type": "TextField", - "validator": { - "regexp": "12345", - "minSize": 5, - "maxSize": 200, - "mandatory": true, - "errorMessages": { - "regexp": "mockedValue, arg1: TestName, arg2: 12345", - "minSize": "mockedValue, arg1: TestName, arg2: 5", - "maxSize": "mockedValue, arg1: TestName, arg2: 200", - "mandatory": "mockedValue, arg1: TestName, arg2: true" - } - } - }, - { - "id": "ZipFieldTest", - "technicalName": "ZipField_ZipFieldTest", - "name": "Postleitzahl", - "hint": "Bitte Ihre Postleitzahl eingeben", - "type": "ZipField", - "validator": { - "regexp": "\\d{5}", - "mandatory": true, - "errorMessages": { - "regexp": "mockedValue, arg1: Postleitzahl, arg2: \\d{5}", - "mandatory": "mockedValue, arg1: Postleitzahl, arg2: true" - } - } - }, - { - "id": "PhoneFieldTest", - "technicalName": "PhoneField_PhoneFieldTest", - "name": "Phone", - "type": "PhoneField" - }, - { - "id": "FaxFieldTest", - "technicalName": "FaxField_FaxFieldTest", - "name": "Fax", - "type": "FaxField" - }, - { - "id": "StreetFieldTest", - "technicalName": "StreetNumberField_StreetFieldTest", - "name": "Street and number", - "type": "StreetNumberField" - }, - { - "id": "NumberField", - "technicalName": "NumberField_NumberField", - "name": "Alter", - "hint": "Geben Sie etwas ein!", - "type": "NumberField", - "validator": { - "minSize": 5, - "maxSize": 200, - "mandatory": true, - "errorMessages": { - "number": "mockedValue, arg1: Alter, arg2: {1}", - "minSize": "mockedValue, arg1: Alter, arg2: 5", - "maxSize": "mockedValue, arg1: Alter, arg2: 200", - "mandatory": "mockedValue, arg1: Alter, arg2: true" - } - } - }, - { - "id": "RadioButtonsMandatory", - "technicalName": "RadioButtonGroup_RadioButtonsMandatory", - "name": "Radio", - "hint": "Wählen Sie einen Button!", - "type": "RadioButtonGroup", - "options": [ + "formElements": [ { - "name": "display_123", - "id": "value_123" + "id": "TextField", + "technicalName": "TextField_TextField", + "name": "TestName", + "hint": "Geben Sie etwas ein!", + "placeholder": "Platzhalter", + "type": "TextField", + "validator": { + "regexp": "12345", + "minSize": 5, + "maxSize": 200, + "mandatory": true, + "errorMessages": { + "regexp": "mockedValue, arg1: TestName, arg2: 12345", + "minSize": "mockedValue, arg1: TestName, arg2: 5", + "maxSize": "mockedValue, arg1: TestName, arg2: 200", + "mandatory": "mockedValue, arg1: TestName, arg2: true" + } + } }, { - "name": "display_456", - "id": "value_456", - "selectedByDefault": true - } - ], - "validator": { - "mandatory": true, - "errorMessages": { - "mandatory": "mockedValue, arg1: Radio, arg2: true" - } - } - }, - { - "id": "myComplexCustomId", - "technicalName": "TextField_myComplexCustomId", - "name": "DependentField", - "type": "TextField", - "advancedSettings": { - "visibility": { - "activated": true, - "elementId": "RadioButtonsOptional", - "value": "value_456" + "id": "ZipFieldTest", + "technicalName": "ZipField_ZipFieldTest", + "name": "Postleitzahl", + "hint": "Bitte Ihre Postleitzahl eingeben", + "type": "ZipField", + "validator": { + "regexp": "\\d{5}", + "mandatory": true, + "errorMessages": { + "regexp": "mockedValue, arg1: Postleitzahl, arg2: \\d{5}", + "mandatory": "mockedValue, arg1: Postleitzahl, arg2: true" + } + } }, - "columnWidth": 3, - "breakAfterElement": true - }, - "validator": { - "mandatory": true, - "errorMessages": { - "mandatory": "mockedValue, arg1: DependentField, arg2: true" - } - } - }, - { - "id": "RadioButtonsOptional", - "technicalName": "RadioButtonGroup_RadioButtonsOptional", - "name": "RadioOptional", - "hint": "Wählen Sie einen Button!", - "type": "RadioButtonGroup", - "options": [ { - "name": "display_123", - "id": "value_123" + "id": "PhoneFieldTest", + "technicalName": "PhoneField_PhoneFieldTest", + "name": "Phone", + "type": "PhoneField" }, { - "name": "display_456", - "id": "value_456" - } - ] - }, - { - "id": "RadioButtonsEmptyValidator", - "technicalName": "RadioButtonGroup_RadioButtonsEmptyValidator", - "name": "RadioEmptyValidator", - "hint": "Wählen Sie einen Button!", - "type": "RadioButtonGroup", - "options": [ + "id": "FaxFieldTest", + "technicalName": "FaxField_FaxFieldTest", + "name": "Fax", + "type": "FaxField" + }, { - "name": "display_123", - "id": "value_123" + "id": "StreetFieldTest", + "technicalName": "StreetNumberField_StreetFieldTest", + "name": "Street and number", + "type": "StreetNumberField" }, { - "name": "display_456", - "id": "value_456" - } - ], - "validator": { - "mandatory": false, - "errorMessages": { - "mandatory": "mockedValue, arg1: RadioEmptyValidator, arg2: false" - } - } - }, - { - "id": "CheckBoxesMandatory", - "technicalName": "CheckBoxesGroup_CheckBoxesMandatory", - "name": "CheckBoxes", - "hint": "Wählen Sie eine CheckBox!", - "type": "CheckBoxesGroup", - "options": [ + "id": "NumberField", + "technicalName": "NumberField_NumberField", + "name": "Alter", + "hint": "Geben Sie etwas ein!", + "type": "NumberField", + "validator": { + "minSize": 5, + "maxSize": 200, + "mandatory": true, + "errorMessages": { + "number": "mockedValue, arg1: Alter, arg2: {1}", + "minSize": "mockedValue, arg1: Alter, arg2: 5", + "maxSize": "mockedValue, arg1: Alter, arg2: 200", + "mandatory": "mockedValue, arg1: Alter, arg2: true" + } + } + }, { - "name": "display_123", - "id": "value_123" + "id": "RadioButtonsMandatory", + "technicalName": "RadioButtonGroup_RadioButtonsMandatory", + "name": "Radio", + "hint": "Wählen Sie einen Button!", + "type": "RadioButtonGroup", + "options": [ + { + "name": "display_123", + "id": "value_123" + }, + { + "name": "display_456", + "id": "value_456", + "selectedByDefault": true + } + ], + "validator": { + "mandatory": true, + "errorMessages": { + "mandatory": "mockedValue, arg1: Radio, arg2: true" + } + } }, { - "name": "display_456", - "id": "value_456", - "selectedByDefault": true - } - ], - "validator": { - "mandatory": true, - "errorMessages": { - "mandatory": "mockedValue, arg1: CheckBoxes, arg2: true" - } - } - }, - { - "id": "CheckBoxesEmptyValidator", - "technicalName": "CheckBoxesGroup_CheckBoxesEmptyValidator", - "name": "CheckBoxesEmptyValidator", - "hint": "Wählen Sie eine CheckBox!", - "type": "CheckBoxesGroup", - "options": [ + "id": "myComplexCustomId", + "technicalName": "TextField_myComplexCustomId", + "name": "DependentField", + "type": "TextField", + "advancedSettings": { + "visibility": { + "activated": true, + "elementId": "RadioButtonsOptional", + "value": "value_456" + }, + "columnWidth": 3, + "breakAfterElement": true + }, + "validator": { + "mandatory": true, + "errorMessages": { + "mandatory": "mockedValue, arg1: DependentField, arg2: true" + } + } + }, { - "name": "display_123", - "id": "value_123" + "id": "RadioButtonsOptional", + "technicalName": "RadioButtonGroup_RadioButtonsOptional", + "name": "RadioOptional", + "hint": "Wählen Sie einen Button!", + "type": "RadioButtonGroup", + "options": [ + { + "name": "display_123", + "id": "value_123" + }, + { + "name": "display_456", + "id": "value_456" + } + ] }, { - "name": "display_456", - "id": "value_456" - } - ], - "validator": { - "mandatory": false, - "errorMessages": { - "mandatory": "mockedValue, arg1: CheckBoxesEmptyValidator, arg2: false" - } - } - }, - { - "id": "SelectBoxMandatory", - "technicalName": "SelectBox_SelectBoxMandatory", - "name": "SelectBox", - "hint": "Wählen Sie eine Option!", - "type": "SelectBox", - "options": [ + "id": "RadioButtonsEmptyValidator", + "technicalName": "RadioButtonGroup_RadioButtonsEmptyValidator", + "name": "RadioEmptyValidator", + "hint": "Wählen Sie einen Button!", + "type": "RadioButtonGroup", + "options": [ + { + "name": "display_123", + "id": "value_123" + }, + { + "name": "display_456", + "id": "value_456" + } + ], + "validator": { + "mandatory": false, + "errorMessages": { + "mandatory": "mockedValue, arg1: RadioEmptyValidator, arg2: false" + } + } + }, { - "name": "display_123", - "id": "value_123" + "id": "CheckBoxesMandatory", + "technicalName": "CheckBoxesGroup_CheckBoxesMandatory", + "name": "CheckBoxes", + "hint": "Wählen Sie eine CheckBox!", + "type": "CheckBoxesGroup", + "options": [ + { + "name": "display_123", + "id": "value_123" + }, + { + "name": "display_456", + "id": "value_456", + "selectedByDefault": true + } + ], + "validator": { + "mandatory": true, + "errorMessages": { + "mandatory": "mockedValue, arg1: CheckBoxes, arg2: true" + } + } }, { - "name": "display_456", - "id": "value_456", - "selectedByDefault": true - } - ], - "validator": { - "mandatory": true, - "errorMessages": { - "mandatory": "mockedValue, arg1: SelectBox, arg2: true" - } - } - }, - { - "id": "SelectBoxOnlyDisplayName", - "technicalName": "SelectBox_SelectBoxOnlyDisplayName", - "name": "SelectBox DisplayName", - "hint": "Wählen Sie eine Option!", - "type": "SelectBox", - "options": [ + "id": "CheckBoxesEmptyValidator", + "technicalName": "CheckBoxesGroup_CheckBoxesEmptyValidator", + "name": "CheckBoxesEmptyValidator", + "hint": "Wählen Sie eine CheckBox!", + "type": "CheckBoxesGroup", + "options": [ + { + "name": "display_123", + "id": "value_123" + }, + { + "name": "display_456", + "id": "value_456" + } + ], + "validator": { + "mandatory": false, + "errorMessages": { + "mandatory": "mockedValue, arg1: CheckBoxesEmptyValidator, arg2: false" + } + } + }, { - "name": "display_123", - "id": "display_123" + "id": "SelectBoxMandatory", + "technicalName": "SelectBox_SelectBoxMandatory", + "name": "SelectBox", + "hint": "Wählen Sie eine Option!", + "type": "SelectBox", + "options": [ + { + "name": "display_123", + "id": "value_123" + }, + { + "name": "display_456", + "id": "value_456", + "selectedByDefault": true + } + ], + "validator": { + "mandatory": true, + "errorMessages": { + "mandatory": "mockedValue, arg1: SelectBox, arg2: true" + } + } }, { - "name": "display_456", - "id": "display_456" - } - ], - "validator": { - "mandatory": true, - "errorMessages": { - "mandatory": "mockedValue, arg1: SelectBox DisplayName, arg2: true" - } - } - }, - { - "id": "SelectBoxEmptyValidator", - "technicalName": "SelectBox_SelectBoxEmptyValidator", - "name": "SelectBoxEmptyValidator", - "hint": "Wählen Sie eine Option!", - "type": "SelectBox", - "options": [ + "id": "SelectBoxOnlyDisplayName", + "technicalName": "SelectBox_SelectBoxOnlyDisplayName", + "name": "SelectBox DisplayName", + "hint": "Wählen Sie eine Option!", + "type": "SelectBox", + "options": [ + { + "name": "display_123", + "id": "display_123" + }, + { + "name": "display_456", + "id": "display_456" + } + ], + "validator": { + "mandatory": true, + "errorMessages": { + "mandatory": "mockedValue, arg1: SelectBox DisplayName, arg2: true" + } + } + }, { - "name": "display_123", - "id": "value_123" + "id": "SelectBoxEmptyValidator", + "technicalName": "SelectBox_SelectBoxEmptyValidator", + "name": "SelectBoxEmptyValidator", + "hint": "Wählen Sie eine Option!", + "type": "SelectBox", + "options": [ + { + "name": "display_123", + "id": "value_123" + }, + { + "name": "display_456", + "id": "value_456" + } + ], + "validator": { + "mandatory": false, + "errorMessages": { + "mandatory": "mockedValue, arg1: SelectBoxEmptyValidator, arg2: false" + } + } }, { - "name": "display_456", - "id": "value_456" - } - ], - "validator": { - "mandatory": false, - "errorMessages": { - "mandatory": "mockedValue, arg1: SelectBoxEmptyValidator, arg2: false" - } - } - }, - { - "id": "TextArea", - "technicalName": "TextArea_TextArea", - "name": "TextArea", - "hint": "Geben Sie etwas ein!", - "type": "TextArea", - "rows": 5, - "columns": 4, - "validator": { - "maxSize": 10, - "mandatory": true, - "errorMessages": { - "maxSize": "mockedValue, arg1: TextArea, arg2: 10", - "mandatory": "mockedValue, arg1: TextArea, arg2: true" - } - } - }, - { - "id": "DateFieldMin", - "technicalName": "DateField_DateFieldMin", - "name": "DateField min", - "hint": "Geben Sie etwas ein!", - "type": "DateField", - "validator": { - "mandatory": true, - "errorMessages": { - "date": "mockedValue, arg1: DateField min, arg2: {1}", - "mandatory": "mockedValue, arg1: DateField min, arg2: true" - } - } - }, - { - "id": "DateFieldMax", - "technicalName": "DateField_DateFieldMax", - "name": "DateField max", - "hint": "Geben Sie etwas ein!", - "type": "DateField", - "validator": { - "mandatory": true, - "errorMessages": { - "date": "mockedValue, arg1: DateField max, arg2: {1}", - "mandatory": "mockedValue, arg1: DateField max, arg2: true" - } - } - }, - { - "id": "TextOnly", - "technicalName": "TextOnly_TextOnly", - "name": "Das ist ein langer Text zur Erklärung des Formulars", - "type": "TextOnly" - }, - { - "id": "UsersMail", - "technicalName": "UsersMail_UsersMail", - "name": "UsersMail", - "hint": "Tragen Sie eine Email-Adresse ein!", - "type": "UsersMail", - "displayCheckbox": false, - "validator": { - "mandatory": true, - "errorMessages": { - "mandatory": "mockedValue, arg1: UsersMail, arg2: true", - "email": "mockedValue, arg1: UsersMail, arg2: {1}" - } - } - }, - { - "id": "FileUpload", - "technicalName": "FileUpload_FileUpload", - "name": "TestName", - "hint": "Laden Sie etwas hoch!", - "type": "FileUpload", - "validator": { - "maxSize": 42, - "minSize": 0, - "mandatory": false, - "errorMessages": { - "maxSize": "mockedValue, arg1: TestName, arg2: 42", - "minSize": "mockedValue, arg1: TestName, arg2: 0", - "mandatory": "mockedValue, arg1: TestName, arg2: false" - } - } - }, - { - "id": "ConsentFormCheckBox", - "technicalName": "ConsentFormCheckBox_ConsentFormCheckBox", - "name": "Data protection consent form", - "hint": "Please confirm the %data protection consent form%", - "type": "ConsentFormCheckBox", - "validator": { - "mandatory": true, - "errorMessages": { - "mandatory": "mockedValue, arg1: Data protection consent form, arg2: true" + "id": "TextArea", + "technicalName": "TextArea_TextArea", + "name": "TextArea", + "hint": "Geben Sie etwas ein!", + "type": "TextArea", + "rows": 5, + "columns": 4, + "validator": { + "maxSize": 10, + "mandatory": true, + "errorMessages": { + "maxSize": "mockedValue, arg1: TextArea, arg2: 10", + "mandatory": "mockedValue, arg1: TextArea, arg2: true" + } + } + }, + { + "id": "DateFieldMin", + "technicalName": "DateField_DateFieldMin", + "name": "DateField min", + "hint": "Geben Sie etwas ein!", + "type": "DateField", + "validator": { + "mandatory": true, + "errorMessages": { + "date": "mockedValue, arg1: DateField min, arg2: {1}", + "mandatory": "mockedValue, arg1: DateField min, arg2: true" + } + } + }, + { + "id": "DateFieldMax", + "technicalName": "DateField_DateFieldMax", + "name": "DateField max", + "hint": "Geben Sie etwas ein!", + "type": "DateField", + "validator": { + "mandatory": true, + "errorMessages": { + "date": "mockedValue, arg1: DateField max, arg2: {1}", + "mandatory": "mockedValue, arg1: DateField max, arg2: true" + } + } + }, + { + "id": "TextOnly", + "technicalName": "TextOnly_TextOnly", + "name": "Das ist ein langer Text zur Erklärung des Formulars", + "type": "TextOnly" + }, + { + "id": "UsersMail", + "technicalName": "UsersMail_UsersMail", + "name": "UsersMail", + "hint": "Tragen Sie eine Email-Adresse ein!", + "type": "UsersMail", + "displayCheckbox": false, + "validator": { + "mandatory": true, + "errorMessages": { + "mandatory": "mockedValue, arg1: UsersMail, arg2: true", + "email": "mockedValue, arg1: UsersMail, arg2: {1}" + } + } + }, + { + "id": "FileUpload", + "technicalName": "FileUpload_FileUpload", + "name": "TestName", + "hint": "Laden Sie etwas hoch!", + "type": "FileUpload", + "validator": { + "maxSize": 42, + "minSize": 0, + "mandatory": false, + "errorMessages": { + "maxSize": "mockedValue, arg1: TestName, arg2: 42", + "minSize": "mockedValue, arg1: TestName, arg2: 0", + "mandatory": "mockedValue, arg1: TestName, arg2: false" + } + } + }, + { + "id": "HiddenField", + "technicalName": "HiddenField_HiddenField", + "name": "HiddenFieldName", + "type": "HiddenField", + "value": "HiddenValue" + }, + { + "id": "ConsentFormCheckBox", + "technicalName": "ConsentFormCheckBox_ConsentFormCheckBox", + "name": "Data protection consent form", + "hint": "Please confirm the %data protection consent form%", + "type": "ConsentFormCheckBox", + "linkTarget": "/8", + "validator": { + "mandatory": true, + "errorMessages": { + "mandatory": "mockedValue, arg1: Data protection consent form, arg2: true" + } + } } - } + ] } ] } diff --git a/form-editor-cae/src/test/resources/com/tallence/formeditor/cae/testdata/expectedConfig-6-20.json b/form-editor-cae/src/test/resources/com/tallence/formeditor/cae/testdata/expectedConfig-6-20.json new file mode 100644 index 00000000..35211816 --- /dev/null +++ b/form-editor-cae/src/test/resources/com/tallence/formeditor/cae/testdata/expectedConfig-6-20.json @@ -0,0 +1,74 @@ +{ + "formActionUrl": "/dynamic/forms/formEditorSubmit/8/20", + "pages": [ + { + "id": "uniquePageId1", + "title": "TestPage 1", + "pageType": "DEFAULT_PAGE", + "formElements": [ + { + "id": "SubTextArea", + "technicalName": "TextArea_SubTextArea", + "name": "SubTextArea", + "hint": "Geben Sie nochmal etwas ein!", + "type": "TextArea", + "rows": 5, + "columns": 4, + "validator": { + "maxSize": 10, + "mandatory": true, + "errorMessages": { + "maxSize": "mockedValue, arg1: SubTextArea, arg2: 10", + "mandatory": "mockedValue, arg1: SubTextArea, arg2: true" + } + } + }, + { + "id": "HiddenField", + "technicalName": "HiddenField_HiddenField", + "name": "HiddenFieldName", + "type": "HiddenField", + "value": "HiddenValue" + } + ] + }, + { + "id": "uniquePageId2", + "title": "TestPage 2", + "pageType": "SUMMARY_PAGE", + "description" : "

      Description of the page

      ", + "formElements": [ + { + "id" : "StreetFieldTest", + "technicalName" : "StreetNumberField_StreetFieldTest", + "name" : "Street and number", + "type" : "StreetNumberField" + }, + { + "id": "TextOnly", + "technicalName": "TextOnly_TextOnly", + "name": "Das ist ein langer Text zur Erklärung des PageTab 2", + "type": "TextOnly" + }, + { + "id" : "NumberField", + "technicalName" : "NumberField_NumberField", + "name" : "Alter", + "hint" : "Geben Sie etwas ein!", + "type" : "NumberField", + "validator" : { + "minSize" : 5, + "maxSize" : 200, + "mandatory" : true, + "errorMessages" : { + "number" : "mockedValue, arg1: Alter, arg2: {1}", + "minSize" : "mockedValue, arg1: Alter, arg2: 5", + "maxSize" : "mockedValue, arg1: Alter, arg2: 200", + "mandatory" : "mockedValue, arg1: Alter, arg2: true" + } + } + } + ] + } + ] +} diff --git a/form-editor-contentbeans-api/src/main/java/com/tallence/formeditor/contentbeans/FormEditor.java b/form-editor-contentbeans-api/src/main/java/com/tallence/formeditor/contentbeans/FormEditor.java index fe5032cb..1f489649 100644 --- a/form-editor-contentbeans-api/src/main/java/com/tallence/formeditor/contentbeans/FormEditor.java +++ b/form-editor-contentbeans-api/src/main/java/com/tallence/formeditor/contentbeans/FormEditor.java @@ -81,4 +81,6 @@ public interface FormEditor extends CMTeasable { Boolean isSpamProtectionEnabled(); + Boolean isPageableFormEnabled(); + } diff --git a/form-editor-contentbeans-lib/src/main/java/com/tallence/formeditor/contentbeans/FormEditorBase.java b/form-editor-contentbeans-lib/src/main/java/com/tallence/formeditor/contentbeans/FormEditorBase.java index 210d62c8..33f240c6 100644 --- a/form-editor-contentbeans-lib/src/main/java/com/tallence/formeditor/contentbeans/FormEditorBase.java +++ b/form-editor-contentbeans-lib/src/main/java/com/tallence/formeditor/contentbeans/FormEditorBase.java @@ -55,4 +55,9 @@ public String getFormAction() { public Boolean isSpamProtectionEnabled() { return getContent().getBoolean(FormEditorHelper.FORM_SPAM_PROTECTION); } + + @Override + public Boolean isPageableFormEnabled() { + return getContent().getBoolean(FormEditorHelper.FORM_PAGEABLE_ENABLED); + } } diff --git a/form-editor-headless-server/src/main/java/com/tallence/formeditor/caas/adapter/FormEditorAdapter.java b/form-editor-headless-server/src/main/java/com/tallence/formeditor/caas/adapter/FormEditorAdapter.java index 5e8e26d3..ff7e7e18 100644 --- a/form-editor-headless-server/src/main/java/com/tallence/formeditor/caas/adapter/FormEditorAdapter.java +++ b/form-editor-headless-server/src/main/java/com/tallence/formeditor/caas/adapter/FormEditorAdapter.java @@ -19,7 +19,6 @@ import com.tallence.formeditor.FormEditorHelper; import com.tallence.formeditor.FormElementFactory; import com.tallence.formeditor.elements.FormElement; -import com.tallence.formeditor.parser.CurrentFormSupplier; import java.util.Arrays; import java.util.List; @@ -36,10 +35,6 @@ public FormEditorAdapter(Content content, FormElementFactory formElementFactory) @SuppressWarnings("unused") public List> formElements() { - - //The formElements parsers might need the locale of the current site. - CurrentFormSupplier.setCurrentForm(content); - return FormEditorHelper.parseFormElements(content, formElementFactory); } diff --git a/form-editor-headless-server/src/main/resources/form-editor-schema.graphql b/form-editor-headless-server/src/main/resources/form-editor-schema.graphql index 979d8a07..32b55dfb 100644 --- a/form-editor-headless-server/src/main/resources/form-editor-schema.graphql +++ b/form-editor-headless-server/src/main/resources/form-editor-schema.graphql @@ -3,6 +3,7 @@ interface FormEditor @inherit(from: ["CMTeasable"]) { adminEmails: [String] formAction: String spamProtectionEnabled: Boolean + pageableFormEnabled: Boolean } type FormEditorImpl implements FormEditor @inherit(from: ["CMTeasableImpl"]) { @@ -10,6 +11,7 @@ type FormEditorImpl implements FormEditor @inherit(from: ["CMTeasableImpl"]) { adminEmails: [String] @fetch(from: "@formEditorAdapter.to(#root).adminEmails()") formAction: String spamProtectionEnabled: Boolean + pageableFormEnabled: Boolean } interface FormElement{ @@ -141,6 +143,12 @@ interface ZipField @inherit(from: ["FormElement"]) { type ZipFieldImpl implements ZipField @inherit(from: ["AbstractFormElement"]) { } +interface HiddenField @inherit(from: ["FormElement"]) { +} + +type HiddenFieldImpl implements HiddenField @inherit(from: ["AbstractFormElement"]) { +} + type ComplexValue { displayName: String value: String diff --git a/form-editor-server/src/main/resources/framework/doctypes/form-editor-doctypes.xml b/form-editor-server/src/main/resources/framework/doctypes/form-editor-doctypes.xml index 56428e40..6a6a2146 100644 --- a/form-editor-server/src/main/resources/framework/doctypes/form-editor-doctypes.xml +++ b/form-editor-server/src/main/resources/framework/doctypes/form-editor-doctypes.xml @@ -13,6 +13,7 @@ + diff --git a/form-editor-shared/pom.xml b/form-editor-shared/pom.xml index fdff9a23..8bbd61a0 100644 --- a/form-editor-shared/pom.xml +++ b/form-editor-shared/pom.xml @@ -37,12 +37,12 @@ com.coremedia.cms cap-multisite - - - org.springframework - spring-beans + com.coremedia.cms + coremedia-xml + + org.springframework spring-core @@ -67,6 +67,11 @@ jakarta.servlet.jsp.jstl-api provided + + javax.inject + javax.inject + provided + org.apache.commons commons-lang3 @@ -82,8 +87,13 @@ provided - org.slf4j - slf4j-api + org.apache.tika + tika-core + + + org.iban4j + iban4j + 3.2.3-RELEASE @@ -92,6 +102,11 @@ spring-test test + + org.springframework + spring-beans + test + junit junit @@ -144,6 +159,7 @@ org.skyscreamer jsonassert test + 1.2.1 commons-io @@ -161,7 +177,7 @@ commons-fileupload commons-fileupload - 1.4 + 1.5 diff --git a/form-editor-shared/src/main/java/com/tallence/formeditor/FormEditorHelper.java b/form-editor-shared/src/main/java/com/tallence/formeditor/FormEditorHelper.java index 8cb2a693..466a5d48 100644 --- a/form-editor-shared/src/main/java/com/tallence/formeditor/FormEditorHelper.java +++ b/form-editor-shared/src/main/java/com/tallence/formeditor/FormEditorHelper.java @@ -9,6 +9,7 @@ import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; @@ -28,6 +29,8 @@ public class FormEditorHelper { public static String FORM_SPAM_PROTECTION = "spamProtectionEnabled"; + public static String FORM_PAGEABLE_ENABLED = "pageableFormEnabled"; + public static String MAIL_ACTION = "mailAction"; public static Optional getFormElements(Content content) { @@ -46,7 +49,7 @@ public static Optional getFormElements(Content content) { } /** - * Resolves the {@link #FORM_ELEMENTS} Struct and transforms the element data into {@link FormElement}s. + * Delegating to {@link #parseFormElements(Map, FormElementFactory)} * @param form the document containing all form elements data * @param formElementFactory the factory to create {@link FormElement} * @return a list of parsed {@link FormElement}s @@ -56,13 +59,24 @@ public static List> parseFormElements(Content form, FormElementFa var formData = getFormElements(form) .map(CapStruct::getProperties) .orElse(Collections.emptyMap()); + return parseFormElements(form, formData, formElementFactory); + } + + /** + * Resolves the {@link #FORM_ELEMENTS} Struct and transforms the element data into {@link FormElement}s. + * @param formData the document containing all form elements data + * @param formElementFactory the factory to create {@link FormElement} + * @return a list of parsed {@link FormElement}s + */ + public static List> parseFormElements(Content form, Map formData, FormElementFactory formElementFactory) { + return formData.entrySet().stream() .filter(e -> e.getValue() instanceof Struct) - .map(e -> parseElement((Struct) e.getValue(), e.getKey(), formElementFactory)) + .map(e -> parseElement(form, (Struct) e.getValue(), e.getKey(), formElementFactory)) .collect(Collectors.toList()); } - private static FormElement parseElement(Struct value, String key, FormElementFactory formElementFactory) { - return formElementFactory.createFormElement(value, key); + private static FormElement parseElement(Content form, Struct value, String key, FormElementFactory formElementFactory) { + return formElementFactory.createFormElement(form, value, key); } } diff --git a/form-editor-shared/src/main/java/com/tallence/formeditor/FormElementFactory.java b/form-editor-shared/src/main/java/com/tallence/formeditor/FormElementFactory.java index 80bb37b5..464984ff 100644 --- a/form-editor-shared/src/main/java/com/tallence/formeditor/FormElementFactory.java +++ b/form-editor-shared/src/main/java/com/tallence/formeditor/FormElementFactory.java @@ -16,9 +16,11 @@ package com.tallence.formeditor; +import com.coremedia.cap.content.Content; import com.coremedia.cap.struct.Struct; import com.tallence.formeditor.elements.FormElement; import com.tallence.formeditor.parser.AbstractFormElementParser; +import com.tallence.formeditor.parser.CurrentFormAwareParser; import edu.umd.cs.findbugs.annotations.NonNull; import org.springframework.stereotype.Component; @@ -42,12 +44,12 @@ public FormElementFactory(List p.getParserKeys().forEach(k -> typeToParser.put(k, p))); } - public > T createFormElement(@NonNull Struct elementData, String id) { - return parseType(elementData, id); + public > T createFormElement(Content form, @NonNull Struct elementData, String id) { + return parseType(form, elementData, id); } - private > T parseType(Struct elementData, String id) { + private > T parseType(Content form, Struct elementData, String id) { String type = elementData.getString(FORM_DATA_KEY_TYPE); @SuppressWarnings("unchecked") @@ -56,7 +58,14 @@ private > T parseType(Struct elementData, String id) { throw new IllegalStateException("Did not find a Parser for type: " + type); } - T formElement = parser.instantiateType(elementData); + T formElement; + if (parser instanceof CurrentFormAwareParser) { + @SuppressWarnings("unchecked") + var currentFormAwareParser = (CurrentFormAwareParser) parser; + formElement = currentFormAwareParser.instantiateType(form, elementData); + } else { + formElement = parser.instantiateType(elementData); + } parser.parseBaseFields(formElement, elementData, id); parser.parseSpecialFields(formElement, elementData); diff --git a/form-editor-shared/src/main/java/com/tallence/formeditor/elements/AbstractFormElement.java b/form-editor-shared/src/main/java/com/tallence/formeditor/elements/AbstractFormElement.java index aeee0789..db69ee9d 100644 --- a/form-editor-shared/src/main/java/com/tallence/formeditor/elements/AbstractFormElement.java +++ b/form-editor-shared/src/main/java/com/tallence/formeditor/elements/AbstractFormElement.java @@ -120,6 +120,11 @@ public void setId(String id) { this.id = id; } + @Override + public String getStructId() { + return this.id; + } + @Override public String getName() { return this.name; diff --git a/form-editor-shared/src/main/java/com/tallence/formeditor/elements/FormElement.java b/form-editor-shared/src/main/java/com/tallence/formeditor/elements/FormElement.java index c8f78f76..055f80a4 100644 --- a/form-editor-shared/src/main/java/com/tallence/formeditor/elements/FormElement.java +++ b/form-editor-shared/src/main/java/com/tallence/formeditor/elements/FormElement.java @@ -21,6 +21,7 @@ import org.springframework.util.MultiValueMap; import javax.servlet.http.HttpServletRequest; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -29,10 +30,18 @@ */ public interface FormElement { + /** + * @return id of the field, gets replaced with customId if available + */ String getId(); void setId(String id); + /** + * @return id of the field, always the generated struct key value, not replaced by customId. + */ + String getStructId(); + String getName(); void setName(String name); @@ -91,4 +100,12 @@ public interface FormElement { void fillFormData(Map formData); void setValue(MultiValueMap postData, HttpServletRequest request); + + /** + * Flattening the formElements of {@link OrderingElement}s before further handling (validation, serializing, etc.) + * @return the list of flattened elements for {@link OrderingElement}s or a singletonList of the element itself otherwise. + */ + default List> flattenFormElements() { + return Collections.singletonList(this); + } } diff --git a/form-editor-shared/src/main/java/com/tallence/formeditor/elements/HiddenField.java b/form-editor-shared/src/main/java/com/tallence/formeditor/elements/HiddenField.java new file mode 100644 index 00000000..03e7b7ab --- /dev/null +++ b/form-editor-shared/src/main/java/com/tallence/formeditor/elements/HiddenField.java @@ -0,0 +1,32 @@ +/* + * Copyright 2022 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.tallence.formeditor.elements; + +import com.tallence.formeditor.validator.TextOnlyValidator; + +/** + * Model bean for a configured HiddenField. + * No special logic required here: the hidden value will be part of the form submit request and + * ist set as a value into this field model via {@link AbstractFormElement#setValue}. + */ +public class HiddenField extends AbstractFormElement { + + public HiddenField() { + super(String.class); + } + +} diff --git a/form-editor-shared/src/main/java/com/tallence/formeditor/elements/IbanField.java b/form-editor-shared/src/main/java/com/tallence/formeditor/elements/IbanField.java new file mode 100644 index 00000000..13fc8285 --- /dev/null +++ b/form-editor-shared/src/main/java/com/tallence/formeditor/elements/IbanField.java @@ -0,0 +1,31 @@ +/* + * Copyright 2022 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.tallence.formeditor.elements; + +import com.tallence.formeditor.validator.IbanFieldValidator; + +/** + * Model bean for a configured IbanField. + * It extends the {@link TextField}. + */ +public class IbanField extends AbstractFormElement { + + public IbanField() { + super(String.class); + } + +} diff --git a/form-editor-shared/src/main/java/com/tallence/formeditor/elements/OrderingElement.java b/form-editor-shared/src/main/java/com/tallence/formeditor/elements/OrderingElement.java new file mode 100644 index 00000000..fb3e1265 --- /dev/null +++ b/form-editor-shared/src/main/java/com/tallence/formeditor/elements/OrderingElement.java @@ -0,0 +1,10 @@ +package com.tallence.formeditor.elements; + +/** + * Marker interface for Ordering elements like a PageElement. + *
      + * Flatten the elements before further handling (validation, serializing, etc.) + */ +public interface OrderingElement { + +} diff --git a/form-editor-shared/src/main/java/com/tallence/formeditor/elements/PageElement.java b/form-editor-shared/src/main/java/com/tallence/formeditor/elements/PageElement.java new file mode 100644 index 00000000..4413e4bb --- /dev/null +++ b/form-editor-shared/src/main/java/com/tallence/formeditor/elements/PageElement.java @@ -0,0 +1,99 @@ +package com.tallence.formeditor.elements; + +import com.coremedia.cap.content.Content; +import com.coremedia.xml.Markup; +import com.tallence.formeditor.validator.PageElementValidator; +import com.tallence.formeditor.validator.ValidationFieldError; +import org.springframework.util.MultiValueMap; + +import javax.servlet.http.HttpServletRequest; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * Ordering formElement, which is used to structure formFields in Pages. Cannot have a value. + */ +public class PageElement extends AbstractFormElement implements OrderingElement { + + private Markup pageDescription; + private PageType pageType; + + private List> subElements; + private final Content currentForm; + + + public PageElement(Content currentForm) { + super(List.class); + this.currentForm = currentForm; + } + + + + @Override + public List getValidationResult() { + throw new IllegalStateException("Page elements cannot be validated. Flatten all elements first and skip the page elements."); + } + + @Override + public boolean dependencyFulfilled(List> allElements) { + throw new IllegalStateException("Page elements cannot be validated. Flatten all elements first and skip the page elements."); + } + + @Override + public void setValue(MultiValueMap postData, HttpServletRequest request) { + throw new IllegalStateException("Page elements cannot be validated. Flatten all elements first and skip the page elements."); + } + + @Override + public String serializeValue() { + throw new IllegalStateException("Page elements cannot be validated. Flatten all elements first and skip the page elements."); + } + + @Override + public void fillFormData(Map formData) { + throw new IllegalStateException("Page elements cannot be validated. Flatten all elements first and skip the page elements."); + } + + public void setSubElements(List> subElements) { + this.subElements = subElements; + } + + @Override + public List> flattenFormElements() { + return Optional.ofNullable(subElements).orElse(Collections.emptyList()); + } + + public List> getSubElements() { + return flattenFormElements(); + } + + public void setPageDescription(Markup pageDescription) { + this.pageDescription = pageDescription; + } + + public Markup getPageDescription() { + return pageDescription; + } + + public PageType getPageType() { + return pageType; + } + + public void setPageType(PageType pageType) { + this.pageType = pageType; + } + + public void setPageType(String pageType) { + setPageType(PageType.valueOf(pageType)); + } + + public Content getCurrentForm() { + return currentForm; + } + + public enum PageType { + DEFAULT_PAGE, SUMMARY_PAGE + } +} diff --git a/form-editor-shared/src/main/java/com/tallence/formeditor/parser/AbstractFormElementParser.java b/form-editor-shared/src/main/java/com/tallence/formeditor/parser/AbstractFormElementParser.java index 723fa259..d633df8a 100644 --- a/form-editor-shared/src/main/java/com/tallence/formeditor/parser/AbstractFormElementParser.java +++ b/form-editor-shared/src/main/java/com/tallence/formeditor/parser/AbstractFormElementParser.java @@ -64,6 +64,7 @@ public abstract class AbstractFormElementParser> { /** * Creates an instance of the concrete parser class. + * Implement {@link CurrentFormAwareParser} if the currentForm content is relevant for the {@link FormElement}. * * @param elementData the element data from which to create the instance */ diff --git a/form-editor-shared/src/main/java/com/tallence/formeditor/parser/ConsentFormCheckBoxParser.java b/form-editor-shared/src/main/java/com/tallence/formeditor/parser/ConsentFormCheckBoxParser.java index 0f71e419..1d415913 100644 --- a/form-editor-shared/src/main/java/com/tallence/formeditor/parser/ConsentFormCheckBoxParser.java +++ b/form-editor-shared/src/main/java/com/tallence/formeditor/parser/ConsentFormCheckBoxParser.java @@ -18,7 +18,6 @@ import com.coremedia.cap.struct.Struct; import com.tallence.formeditor.elements.ConsentFormCheckBox; import com.tallence.formeditor.validator.ConsentFormCheckboxValidator; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import static com.coremedia.cap.util.CapStructUtil.*; diff --git a/form-editor-shared/src/main/java/com/tallence/formeditor/parser/CurrentFormAwareParser.java b/form-editor-shared/src/main/java/com/tallence/formeditor/parser/CurrentFormAwareParser.java new file mode 100644 index 00000000..b52e675f --- /dev/null +++ b/form-editor-shared/src/main/java/com/tallence/formeditor/parser/CurrentFormAwareParser.java @@ -0,0 +1,15 @@ +package com.tallence.formeditor.parser; + +import com.coremedia.cap.content.Content; +import com.coremedia.cap.struct.Struct; +import com.tallence.formeditor.elements.FormElement; + +/** + * Can be implemented if the currentForm is required by the elements. E.g. for using the settingsService. + * The {@link com.tallence.formeditor.FormElementFactory} will handle this case. + * @param + */ +public interface CurrentFormAwareParser> { + + T instantiateType(Content currentForm, Struct elementData); +} diff --git a/form-editor-shared/src/main/java/com/tallence/formeditor/parser/CurrentFormSupplier.java b/form-editor-shared/src/main/java/com/tallence/formeditor/parser/CurrentFormSupplier.java deleted file mode 100644 index ca3be2a0..00000000 --- a/form-editor-shared/src/main/java/com/tallence/formeditor/parser/CurrentFormSupplier.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.tallence.formeditor.parser; - -import com.coremedia.cap.content.Content; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; -import org.springframework.web.context.request.RequestAttributes; -import org.springframework.web.context.request.RequestContextHolder; - -import java.util.function.Supplier; - -import static java.util.Optional.ofNullable; - -/** - * Provides the current form content based on the {@link RequestContextHolder}. - * Similar to com.coremedia.blueprint.cae.constants.RequestAttributeConstants - */ -@Component -public class CurrentFormSupplier implements Supplier { - - private static final Logger LOG = LoggerFactory.getLogger(CurrentFormSupplier.class); - - private static final String CURRENT_FORM = "currentForm"; - - @Override - public Content get() { - - var currentForm = (Content) ofNullable(RequestContextHolder.getRequestAttributes()) - .map(a -> a.getAttribute(CURRENT_FORM, RequestAttributes.SCOPE_REQUEST)) - .filter(l -> l instanceof Content) - .orElse(null); - - if (currentForm == null) { - LOG.error("No current form set into the request! Cannot parse all form fields."); - } - return currentForm; - } - - public static void setCurrentForm(Content currentForm) { - ofNullable(RequestContextHolder.getRequestAttributes()) - .orElseThrow(() -> new IllegalStateException("No RequestAttributes available, cannot set the currect form")) - .setAttribute(CURRENT_FORM, currentForm, RequestAttributes.SCOPE_REQUEST); - } -} diff --git a/form-editor-shared/src/main/java/com/tallence/formeditor/parser/DateFieldParser.java b/form-editor-shared/src/main/java/com/tallence/formeditor/parser/DateFieldParser.java index e8938893..672f1b14 100644 --- a/form-editor-shared/src/main/java/com/tallence/formeditor/parser/DateFieldParser.java +++ b/form-editor-shared/src/main/java/com/tallence/formeditor/parser/DateFieldParser.java @@ -26,7 +26,6 @@ import java.time.LocalDate; import java.util.Locale; import java.util.Optional; -import java.util.function.Supplier; import static com.coremedia.cap.util.CapStructUtil.getBoolean; import static com.coremedia.cap.util.CapStructUtil.getSubstruct; @@ -36,21 +35,24 @@ * Parser for elements of type {@link DateField} */ @Component -public class DateFieldParser extends AbstractFormElementParser { +public class DateFieldParser extends AbstractFormElementParser implements CurrentFormAwareParser { public static final String parserKey = "DateField"; - private final Supplier currentFormSupplier; private final SitesService sitesService; - public DateFieldParser(Supplier currentFormSupplier, SitesService sitesService) { - this.currentFormSupplier = currentFormSupplier; + public DateFieldParser(SitesService sitesService) { this.sitesService = sitesService; } @Override public DateField instantiateType(Struct elementData) { - return new DateField(getCurrentLocale()); + throw new IllegalStateException("This should not be called, because we need the currentForm"); + } + + @Override + public DateField instantiateType(Content currentForm, Struct elementData) { + return new DateField(getCurrentLocale(currentForm)); } @Override @@ -75,9 +77,9 @@ public String getParserKey() { return parserKey; } - private Locale getCurrentLocale() { + private Locale getCurrentLocale(Content currentForm) { - return Optional.ofNullable(currentFormSupplier.get()) + return Optional.of(currentForm) .map(c -> sitesService.getContentSiteAspect(c).getLocale()) .orElse(Locale.GERMANY); } diff --git a/form-editor-shared/src/main/java/com/tallence/formeditor/parser/HiddenFieldParser.java b/form-editor-shared/src/main/java/com/tallence/formeditor/parser/HiddenFieldParser.java new file mode 100644 index 00000000..dc17b034 --- /dev/null +++ b/form-editor-shared/src/main/java/com/tallence/formeditor/parser/HiddenFieldParser.java @@ -0,0 +1,49 @@ +/* + * Copyright 2022 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.tallence.formeditor.parser; + +import com.coremedia.cap.struct.Struct; +import com.tallence.formeditor.elements.HiddenField; +import org.springframework.stereotype.Component; + +import static com.coremedia.cap.util.CapStructUtil.getString; + +/** + * Parser for elements of type {@link HiddenField} + */ +@Component +public class HiddenFieldParser extends AbstractFormElementParser { + + public static final String HIDDEN_FIELD_VALUE = "value"; + + public static final String parserKey = "HiddenField"; + + @Override + public HiddenField instantiateType(Struct elementData) { + return new HiddenField(); + } + + @Override + public void parseSpecialFields(HiddenField formElement, Struct elementData) { + formElement.setValue(getString(elementData, HIDDEN_FIELD_VALUE)); + } + + @Override + public String getParserKey() { + return parserKey; + } +} diff --git a/form-editor-shared/src/main/java/com/tallence/formeditor/parser/IbanFieldParser.java b/form-editor-shared/src/main/java/com/tallence/formeditor/parser/IbanFieldParser.java new file mode 100644 index 00000000..4cb5fb74 --- /dev/null +++ b/form-editor-shared/src/main/java/com/tallence/formeditor/parser/IbanFieldParser.java @@ -0,0 +1,55 @@ +/* + * Copyright 2022 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.tallence.formeditor.parser; + +import com.coremedia.cap.struct.Struct; +import com.tallence.formeditor.elements.IbanField; +import com.tallence.formeditor.validator.IbanFieldValidator; +import org.springframework.stereotype.Component; + +import static com.coremedia.cap.util.CapStructUtil.getBoolean; +import static com.coremedia.cap.util.CapStructUtil.getSubstruct; +import static java.util.Optional.ofNullable; + +/** + * Parser for elements of type {@link IbanField} + */ +@Component +public class IbanFieldParser extends AbstractFormElementParser { + + public static final String parserKey = "IbanField"; + + @Override + public IbanField instantiateType(Struct elementData) { + return new IbanField(); + } + + @Override + public void parseSpecialFields(IbanField formElement, Struct elementData) { + ofNullable(getSubstruct(elementData, FORM_DATA_VALIDATOR)).ifPresent(validator -> { + IbanFieldValidator ibanFieldValidator = new IbanFieldValidator(); + + ibanFieldValidator.setMandatory(getBoolean(validator, FORM_VALIDATOR_MANDATORY)); + formElement.setValidator(ibanFieldValidator); + }); + } + + @Override + public String getParserKey() { + return parserKey; + } +} diff --git a/form-editor-shared/src/main/java/com/tallence/formeditor/parser/PageElementParser.java b/form-editor-shared/src/main/java/com/tallence/formeditor/parser/PageElementParser.java new file mode 100644 index 00000000..032c23c0 --- /dev/null +++ b/form-editor-shared/src/main/java/com/tallence/formeditor/parser/PageElementParser.java @@ -0,0 +1,68 @@ +package com.tallence.formeditor.parser; + +import com.coremedia.cap.common.CapStruct; +import com.coremedia.cap.content.Content; +import com.coremedia.cap.struct.Struct; +import com.tallence.formeditor.FormEditorHelper; +import com.tallence.formeditor.FormElementFactory; +import com.tallence.formeditor.elements.PageElement; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +import javax.inject.Inject; +import java.util.Collections; +import java.util.Optional; + +import static com.coremedia.cap.common.CapStructHelper.getStruct; +import static com.tallence.formeditor.FormEditorHelper.FORM_ELEMENTS; + +@Component +public class PageElementParser extends AbstractFormElementParser implements CurrentFormAwareParser { + + public static final String parserKey = "PageElement"; + + /** + * Inject the factory lazy to avoid a circular reference: the factory injects all parser beans. + */ + @Lazy + @Inject + private FormElementFactory formElementFactory; + + @Override + public PageElement instantiateType(Struct elementData) { + throw new IllegalStateException("This should not be called, because we need the currentForm"); + } + + @Override + public PageElement instantiateType(Content currentForm, Struct elementData) { + return new PageElement(currentForm); + } + + /** + * Parse the subElements of the page. + * @param formElement the current form element which is not filled completely yet. + * @param elementData the struct representation of the current form field. + */ + @Override + public void parseSpecialFields(PageElement formElement, Struct elementData) { + + var formData = Optional.ofNullable(getStruct(elementData, FORM_ELEMENTS)) + .map(CapStruct::getProperties) + .orElse(Collections.emptyMap()); + + var formElements = FormEditorHelper.parseFormElements(formElement.getCurrentForm(), formData, formElementFactory); + formElement.setSubElements(formElements); + + var pageDescription = elementData.get("pageDescription") != null ? elementData.getMarkup("pageDescription") : null; + formElement.setPageDescription(pageDescription); + + var pageType = elementData.getString("pageType"); + formElement.setPageType(pageType); + + } + + @Override + public String getParserKey() { + return parserKey; + } +} diff --git a/form-editor-shared/src/main/java/com/tallence/formeditor/parser/UsersMailParser.java b/form-editor-shared/src/main/java/com/tallence/formeditor/parser/UsersMailParser.java index 3d123c3f..c1b36a7f 100644 --- a/form-editor-shared/src/main/java/com/tallence/formeditor/parser/UsersMailParser.java +++ b/form-editor-shared/src/main/java/com/tallence/formeditor/parser/UsersMailParser.java @@ -20,6 +20,7 @@ import com.tallence.formeditor.elements.UsersMail; import com.tallence.formeditor.validator.UsersMailValidator; import org.springframework.stereotype.Component; +import org.apache.commons.lang3.StringUtils; import static com.coremedia.cap.util.CapStructUtil.*; import static java.util.Optional.ofNullable; @@ -35,17 +36,17 @@ public class UsersMailParser extends AbstractFormElementParser { public static final String parserKey = "UsersMail"; - @Override public UsersMail instantiateType(Struct elementData) { return new UsersMail(); } - @Override public void parseSpecialFields(UsersMail formElement, Struct elementData) { - if (elementData.get(COPY_TYPE) != null) { - formElement.setCopyBoxOption(UsersMail.CopyBoxOption.valueOf(elementData.getString(COPY_TYPE))); + + String copyType = getString(elementData, COPY_TYPE); + if (StringUtils.isNotBlank(copyType)) { + formElement.setCopyBoxOption(UsersMail.CopyBoxOption.valueOf(copyType)); } else if (elementData.get(LEGACY_COPY) != null && elementData.getBoolean(LEGACY_COPY)) { formElement.setCopyBoxOption(UsersMail.CopyBoxOption.CHECKBOX); } diff --git a/form-editor-shared/src/main/java/com/tallence/formeditor/validator/FileUploadValidator.java b/form-editor-shared/src/main/java/com/tallence/formeditor/validator/FileUploadValidator.java index 376e7d7d..8fcebb2b 100644 --- a/form-editor-shared/src/main/java/com/tallence/formeditor/validator/FileUploadValidator.java +++ b/form-editor-shared/src/main/java/com/tallence/formeditor/validator/FileUploadValidator.java @@ -18,8 +18,10 @@ import com.tallence.formeditor.elements.FileUpload; import com.tallence.formeditor.validator.annotation.ValidationProperty; +import org.apache.tika.Tika; import org.springframework.web.multipart.MultipartFile; +import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -33,6 +35,7 @@ public class FileUploadValidator implements SizeValidator { private static final String MESSAGE_KEY_FILEUPLOAD_MAX = "com.tallence.forms.fileupload.max"; private final FileUpload fileUpload; + private final Tika tika; @ValidationProperty(messageKey = MESSAGE_KEY_FILEUPLOAD_REQUIRED) private boolean mandatory; @@ -46,6 +49,7 @@ public class FileUploadValidator implements SizeValidator { public FileUploadValidator(FileUpload fileUpload) { this.fileUpload = fileUpload; + this.tika = new Tika(); } @Override @@ -64,6 +68,18 @@ public List validate(MultipartFile value) { errors.add(new ValidationFieldError(MESSAGE_KEY_FILEUPLOAD_MAX, this.maxSize)); } + if (value != null) { + //Check if the file-name extension is equal to the mimeType, based on the file data (magic numbers). If not, the file should be blocked for security reasons + try { + var result = tika.detect(value.getBytes()); + if (!result.equalsIgnoreCase(value.getContentType())) { + errors.add(new ValidationFieldError("com.tallence.forms.fileupload.mimetypeMismatch")); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + return errors; } diff --git a/form-editor-shared/src/main/java/com/tallence/formeditor/validator/IbanFieldValidator.java b/form-editor-shared/src/main/java/com/tallence/formeditor/validator/IbanFieldValidator.java new file mode 100644 index 00000000..b9dbadd8 --- /dev/null +++ b/form-editor-shared/src/main/java/com/tallence/formeditor/validator/IbanFieldValidator.java @@ -0,0 +1,72 @@ +/* + * Copyright 2022 Tallence AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.tallence.formeditor.validator; + +import com.tallence.formeditor.elements.IbanField; +import com.tallence.formeditor.validator.annotation.ValidationMessage; +import com.tallence.formeditor.validator.annotation.ValidationProperty; +import org.apache.commons.lang3.StringUtils; +import org.iban4j.IbanFormatException; +import org.iban4j.IbanUtil; +import org.iban4j.InvalidCheckDigitException; +import org.iban4j.UnsupportedCountryException; + +import java.util.Collections; +import java.util.List; + +/** + * Validator for elements of type {@link IbanField}. IBAN Validation is done with iban4j + * (https://github.com/arturmkrtchyan/iban4j) and is ISO_13616 and ISO_9362 compatible. + */ +@ValidationMessage(name = "iban", messageKey = IbanFieldValidator.MESSAGE_KEY_IBANFIELD_PATTERN) +public class IbanFieldValidator implements Validator { + + private static final String MESSAGE_KEY_IBANFIELD_MANDATORY = "com.tallence.forms.ibanField.mandatory"; + protected static final String MESSAGE_KEY_IBANFIELD_PATTERN = "com.tallence.forms.ibanField.invalid"; + + @ValidationProperty(messageKey = MESSAGE_KEY_IBANFIELD_MANDATORY) + private boolean mandatory; + + @Override + public List validate(String value) { + + if (StringUtils.isBlank(value) && mandatory) { + return Collections.singletonList(new ValidationFieldError(MESSAGE_KEY_IBANFIELD_MANDATORY)); + } + + if (!StringUtils.isBlank(value)) { + try { + IbanUtil.validate(value.replaceAll("\\s+","")); + } catch (IbanFormatException | InvalidCheckDigitException | UnsupportedCountryException e) { + return Collections.singletonList(new ValidationFieldError(MESSAGE_KEY_IBANFIELD_PATTERN)); + } + } + + + return Collections.emptyList(); + } + + @Override + public boolean isMandatory() { + return this.mandatory; + } + + public void setMandatory(boolean mandatory) { + this.mandatory = mandatory; + } + +} diff --git a/form-editor-shared/src/main/java/com/tallence/formeditor/validator/PageElementValidator.java b/form-editor-shared/src/main/java/com/tallence/formeditor/validator/PageElementValidator.java new file mode 100644 index 00000000..bd5e57f9 --- /dev/null +++ b/form-editor-shared/src/main/java/com/tallence/formeditor/validator/PageElementValidator.java @@ -0,0 +1,16 @@ +package com.tallence.formeditor.validator; + +import java.util.List; + +public class PageElementValidator implements Validator { + + @Override + public List validate(List value) { + throw new IllegalStateException("Page elements cannot be validated. Flatten all elements first and skip the page elements."); + } + + @Override + public boolean isMandatory() { + return false; + } +} diff --git a/form-editor-shared/src/test/java/com/tallence/formeditor/FormElementFactoryTest.java b/form-editor-shared/src/test/java/com/tallence/formeditor/FormElementFactoryTest.java index 85effdbf..26e6226a 100644 --- a/form-editor-shared/src/test/java/com/tallence/formeditor/FormElementFactoryTest.java +++ b/form-editor-shared/src/test/java/com/tallence/formeditor/FormElementFactoryTest.java @@ -98,7 +98,7 @@ private > T getTestFormElement(String id) { if (element == null) { return null; } - return this.factory.createFormElement(element, id); + return this.factory.createFormElement(form, element, id); } @Test diff --git a/form-editor-studio-lib/pom.xml b/form-editor-studio-lib/pom.xml index 18a9a0e2..40109b9f 100644 --- a/form-editor-studio-lib/pom.xml +++ b/form-editor-studio-lib/pom.xml @@ -76,6 +76,8 @@ org.springframework spring-beans + + provided org.springframework @@ -86,6 +88,13 @@ spring-context + + + jakarta.servlet + jakarta.servlet-api + provided + + com.coremedia.cms @@ -117,6 +126,11 @@ cap-client-xml test + + org.springframework + spring-web + test + diff --git a/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/FormEditorValidator.java b/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/FormEditorValidator.java index c3e544a9..522aa752 100644 --- a/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/FormEditorValidator.java +++ b/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/FormEditorValidator.java @@ -24,12 +24,16 @@ import com.tallence.formeditor.FormEditorHelper; import com.tallence.formeditor.FormElementFactory; import com.tallence.formeditor.elements.FormElement; +import com.tallence.formeditor.elements.PageElement; +import com.tallence.formeditor.studio.validator.field.ComplexValidator; import com.tallence.formeditor.studio.validator.field.FieldValidator; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.StringUtils; import java.util.List; import java.util.Locale; +import java.util.stream.Collectors; + +import static com.tallence.formeditor.elements.PageElement.PageType.SUMMARY_PAGE; /** * Validates, that a form with form action "mailAction" does not have a fileUpload-field and has a mail-address entered. @@ -39,15 +43,18 @@ public class FormEditorValidator extends ContentTypeValidatorBase { private final ThreadLocal localeThreadLocal; private final FormElementFactory formElementFactory; private final SitesService sitesService; + private final List fieldValidators; + private final List complexValidators; - public FormEditorValidator(ThreadLocal localeThreadLocal, FormElementFactory formElementFactory, SitesService sitesService) { + public FormEditorValidator(ThreadLocal localeThreadLocal, FormElementFactory formElementFactory, SitesService sitesService, + List fieldValidators, List complexValidators) { this.localeThreadLocal = localeThreadLocal; this.formElementFactory = formElementFactory; this.sitesService = sitesService; + this.fieldValidators = fieldValidators; + this.complexValidators = complexValidators; } - @Autowired - private List fieldValidators; //Can be overwritten, see the setters below private String formActionProperty = FormEditorHelper.FORM_ACTION; @@ -58,8 +65,25 @@ public void validate(Content content, Issues issues) { // Validate form fields localeThreadLocal.set(sitesService.getContentSiteAspect(content).getLocale()); - FormEditorHelper.parseFormElements(content, formElementFactory) - .forEach(formElement -> validateFormElement(issues, action, formElement)); + var formElements = FormEditorHelper.parseFormElements(content, formElementFactory); + formElements.forEach(formElement -> validateFormElement(issues, action, formElement)); + + complexValidators.forEach(complexValidator -> complexValidator.validateFieldIfResponsible(formElements, action, issues, content)); + + if (formElements.stream().anyMatch(f -> f instanceof PageElement) && + formElements.stream().anyMatch(f -> !(f instanceof PageElement))) { + //Expect only PageElements or no PageElement + issues.addIssue(Severity.ERROR, FormEditorHelper.FORM_DATA, "formField_ordering_error"); + } + + var pageElements = formElements.stream().filter(e -> e instanceof PageElement).map(e -> ((PageElement) e)).collect(Collectors.toList()); + var summaryPages = pageElements.stream().filter(p -> p.getPageType().equals(SUMMARY_PAGE)).collect(Collectors.toList()); + if (summaryPages.size() > 1) { + issues.addIssue(Severity.ERROR, FormEditorHelper.FORM_DATA, "formField_summaryPage_multiple_error"); + } else if (!summaryPages.isEmpty() && pageElements.indexOf(summaryPages.get(0)) != (pageElements.size() - 1)) { + issues.addIssue(Severity.ERROR, FormEditorHelper.FORM_DATA, "formField_summaryPage_middle_error"); + } + // Further validations if (FormEditorHelper.MAIL_ACTION.equals(action) && !StringUtils.hasText(content.getString(FormEditorHelper.ADMIN_MAILS))) { diff --git a/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/FormStudioValidatorConfiguration.java b/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/FormStudioValidatorConfiguration.java index 517ba3dc..46d44358 100644 --- a/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/FormStudioValidatorConfiguration.java +++ b/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/FormStudioValidatorConfiguration.java @@ -19,12 +19,15 @@ import com.coremedia.cap.multisite.SitesService; import com.coremedia.cap.multisite.impl.MultiSiteConfiguration; import com.tallence.formeditor.FormElementFactory; +import com.tallence.formeditor.studio.validator.field.ComplexValidator; +import com.tallence.formeditor.studio.validator.field.FieldValidator; import com.tallence.formeditor.contentbeans.FormEditor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import java.util.List; import java.util.Locale; import java.util.function.Supplier; @@ -35,8 +38,11 @@ public class FormStudioValidatorConfiguration { @Bean public FormEditorValidator createFormEditorValidator(CapConnection connection, FormElementFactory formElementFactory, - ThreadLocal localeThreadLocal, SitesService sitesService) { - final var formEditorValidator = new FormEditorValidator(localeThreadLocal, formElementFactory, sitesService); + ThreadLocal localeThreadLocal, SitesService sitesService, + List fieldValidators, + List complexValidators) { + final var formEditorValidator = new FormEditorValidator(localeThreadLocal, formElementFactory, sitesService, + fieldValidators, complexValidators); formEditorValidator.setContentType(FormEditor.NAME); formEditorValidator.setConnection(connection); diff --git a/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/CheckBoxesRestrictionsValidator.java b/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/CheckBoxesRestrictionsValidator.java index 690e53d8..68faf8b5 100644 --- a/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/CheckBoxesRestrictionsValidator.java +++ b/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/CheckBoxesRestrictionsValidator.java @@ -51,25 +51,25 @@ public void validateField(CheckBoxesGroup formElement, String action, Issues iss if (minSelection != null) { if (minSelection < 0) { - addErrorIssue(issues, formElement.getId(), FULLPATH_MIN_SIZE, "checkboxes_options_min_lower_zero", formElement.getName()); + addErrorIssue(issues, formElement.getStructId(), FULLPATH_MIN_SIZE, "checkboxes_options_min_lower_zero", formElement.getName()); } if (allOptions < minSelection) { - addErrorIssue(issues, formElement.getId(), FULLPATH_MIN_SIZE, "checkboxes_options_min_greater_options", formElement.getName()); + addErrorIssue(issues, formElement.getStructId(), FULLPATH_MIN_SIZE, "checkboxes_options_min_greater_options", formElement.getName()); } } if (maxSelection != null) { if (maxSelection < 0) { - addErrorIssue(issues, formElement.getId(), FULLPATH_MAX_SIZE, "checkboxes_options_max_lower_zero", formElement.getName()); + addErrorIssue(issues, formElement.getStructId(), FULLPATH_MAX_SIZE, "checkboxes_options_max_lower_zero", formElement.getName()); } if (allOptions < maxSelection) { - addErrorIssue(issues, formElement.getId(), FULLPATH_MAX_SIZE, "checkboxes_options_max_lower_options", formElement.getName()); + addErrorIssue(issues, formElement.getStructId(), FULLPATH_MAX_SIZE, "checkboxes_options_max_lower_options", formElement.getName()); } if (selectedOptions > maxSelection) { - addErrorIssue(issues, formElement.getId(), FULLPATH_MAX_SIZE, "checkboxes_options_max_lower_preselection", formElement.getName()); + addErrorIssue(issues, formElement.getStructId(), FULLPATH_MAX_SIZE, "checkboxes_options_max_lower_preselection", formElement.getName()); } } if (minSelection != null && maxSelection != null && minSelection > maxSelection) { - addErrorIssue(issues, formElement.getId(), FULLPATH_MAX_SIZE, "checkboxes_options_max_lower_min", formElement.getName()); + addErrorIssue(issues, formElement.getStructId(), FULLPATH_MAX_SIZE, "checkboxes_options_max_lower_min", formElement.getName()); } } diff --git a/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/ComplexValidator.java b/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/ComplexValidator.java new file mode 100644 index 00000000..dae623af --- /dev/null +++ b/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/ComplexValidator.java @@ -0,0 +1,25 @@ +package com.tallence.formeditor.studio.validator.field; + +import com.coremedia.cap.content.Content; +import com.coremedia.rest.validation.Issues; +import com.tallence.formeditor.elements.FormElement; + +import java.util.List; + +/** + * Defines a more complex interface for form editor validators compared to {@link FieldValidator}. + * May take other formElements and the form documents into account. + */ +public interface ComplexValidator { + + /** + * Validates a form and it's fields. + * + * @param formElements the parsed {@link FormElement}s + * @param action the current action of the form (some validators need this). + * @param issues the Issues object for the current validation request. + * @param document the document, containing the struct property with all forms. + */ + void validateFieldIfResponsible(List> formElements, String action, Issues issues, Content document); + +} diff --git a/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/ConsentFormValidator.java b/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/ConsentFormValidator.java index 8541e8c3..2e597dfb 100644 --- a/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/ConsentFormValidator.java +++ b/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/ConsentFormValidator.java @@ -39,14 +39,14 @@ void validateField(ConsentFormCheckBox formElement, String action, Issues issues String name = formElement.getName(); if (formElement.getLinkTarget() == null) { - addErrorIssue(issues, formElement.getId(), FORM_LINK_TARGET, "consentForm_missing_linkTarget", name); + addErrorIssue(issues, formElement.getStructId(), FORM_LINK_TARGET, "consentForm_missing_linkTarget", name); } String hint = formElement.getHint(); if (StringUtils.isEmpty(hint)) { - addErrorIssue(issues, formElement.getId(), FORM_DATA_HINT, "consentForm_missing_hint", name); + addErrorIssue(issues, formElement.getStructId(), FORM_DATA_HINT, "consentForm_missing_hint", name); } else if (!hint.matches(".*%.+%.*")) { - addErrorIssue(issues, formElement.getId(), FORM_DATA_HINT, "consentForm_invalid_hint", name); + addErrorIssue(issues, formElement.getStructId(), FORM_DATA_HINT, "consentForm_invalid_hint", name); } } } diff --git a/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/DuplicateIdValidator.java b/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/DuplicateIdValidator.java new file mode 100644 index 00000000..03bf6bc3 --- /dev/null +++ b/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/DuplicateIdValidator.java @@ -0,0 +1,43 @@ +package com.tallence.formeditor.studio.validator.field; + +import com.coremedia.cap.content.Content; +import com.coremedia.rest.validation.Issues; +import com.coremedia.rest.validation.Severity; +import com.tallence.formeditor.elements.AdvancedSettings; +import com.tallence.formeditor.elements.FormElement; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import static com.tallence.formeditor.FormEditorHelper.FORM_DATA; + +/** + * Making sure, there are no formElements with duplicate IDs or customIDs. + */ +@Component +public class DuplicateIdValidator implements ComplexValidator { + + public static final String FORMFIELD_VALIDATOR_DUPLICATE_ID_ERROR_CODE = "formfield_validator_duplicate_id"; + + @Override + public void validateFieldIfResponsible(List> formElements, String action, Issues issues, Content document) { + + var ids = formElements.stream() + .map(this::getEffectiveId) + .collect(Collectors.toList()); + + ids.stream().filter(i -> Collections.frequency(ids, i) > 1).findFirst() + .ifPresent(duplicateId -> issues.addIssue(Severity.ERROR, FORM_DATA, FORMFIELD_VALIDATOR_DUPLICATE_ID_ERROR_CODE, duplicateId)); + } + + private String getEffectiveId(FormElement formElement) { + return Optional.ofNullable(formElement.getAdvancedSettings()) + .map(AdvancedSettings::getCustomId) + .filter(StringUtils::hasLength) + .orElse(formElement.getId()); + } +} diff --git a/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/NameNotEmptyValidator.java b/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/NameNotEmptyValidator.java index 6f00841c..b499c897 100644 --- a/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/NameNotEmptyValidator.java +++ b/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/NameNotEmptyValidator.java @@ -39,7 +39,7 @@ public NameNotEmptyValidator() { @Override void validateField(AbstractFormElement formElement, String action, Issues issues) { if (StringUtils.isEmpty(formElement.getName())) { - addErrorIssue(issues, formElement.getId(), FORM_DATA_NAME, "formField_missing_name", formElement.getClass().getSimpleName()); + addErrorIssue(issues, formElement.getStructId(), FORM_DATA_NAME, "formField_missing_name", formElement.getClass().getSimpleName()); } } diff --git a/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/NoFileUploadOnMailActionValidator.java b/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/NoFileUploadOnMailActionValidator.java index 521e9d31..26e454a7 100644 --- a/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/NoFileUploadOnMailActionValidator.java +++ b/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/NoFileUploadOnMailActionValidator.java @@ -36,7 +36,7 @@ public NoFileUploadOnMailActionValidator() { @Override void validateField(FileUpload formElement, String action, Issues issues) { if (FormEditor.MAIL_ACTION.equals(action)) { - addErrorIssue(issues, formElement.getId(), FORM_DATA_NAME, "form_action_mail_file"); + addErrorIssue(issues, formElement.getStructId(), FORM_DATA_NAME, "form_action_mail_file"); } } } diff --git a/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/NumberFieldValidator.java b/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/NumberFieldValidator.java index dff83630..7d3a5e6e 100644 --- a/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/NumberFieldValidator.java +++ b/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/NumberFieldValidator.java @@ -34,7 +34,7 @@ public NumberFieldValidator() { void validateField(NumberField formElement, String action, Issues issues) { var validator = formElement.getValidator(); if (validator != null) { - validateMaxAndMinSize(validator, issues, formElement.getId(), formElement.getName()); + validateMaxAndMinSize(validator, issues, formElement.getStructId(), formElement.getName()); } } diff --git a/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/OptionsNotEmptyValidator.java b/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/OptionsNotEmptyValidator.java index b716fa18..10979630 100644 --- a/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/OptionsNotEmptyValidator.java +++ b/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/OptionsNotEmptyValidator.java @@ -38,7 +38,7 @@ void validateField(FieldWithOptions formElement, String action, Issues issues if (formElement.getOptions().isEmpty()) { String messageKey = formElement.getClass().getSimpleName().toLowerCase() + "_missing_options"; - addErrorIssue(issues, formElement.getId(), FORM_GROUP_ELEMENTS_PROPERTY_NAME, messageKey, formElement.getName()); + addErrorIssue(issues, formElement.getStructId(), FORM_GROUP_ELEMENTS_PROPERTY_NAME, messageKey, formElement.getName()); } } diff --git a/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/TextAreaValidator.java b/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/TextAreaValidator.java index a1264b30..d6128199 100644 --- a/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/TextAreaValidator.java +++ b/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/TextAreaValidator.java @@ -34,7 +34,7 @@ public TextAreaValidator() { void validateField(TextArea formElement, String action, Issues issues) { var validator = formElement.getValidator(); if (validator != null) { - validateMaxAndMinSize(validator, issues, formElement.getId(), formElement.getName()); + validateMaxAndMinSize(validator, issues, formElement.getStructId(), formElement.getName()); } } diff --git a/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/TextFieldValidator.java b/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/TextFieldValidator.java index 9c889228..96eea205 100644 --- a/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/TextFieldValidator.java +++ b/form-editor-studio-lib/src/main/java/com/tallence/formeditor/studio/validator/field/TextFieldValidator.java @@ -43,7 +43,7 @@ public TextFieldValidator() { void validateField(TextField formElement, String action, Issues issues) { var validator = formElement.getValidator(); if (validator != null) { - validateFieldValidators(validator, issues, formElement.getId(), formElement.getName()); + validateFieldValidators(validator, issues, formElement.getStructId(), formElement.getName()); } } diff --git a/form-editor-studio-lib/src/test/java/com/tallence/formeditor/studio/validator/FormEditorValidatorTest.java b/form-editor-studio-lib/src/test/java/com/tallence/formeditor/studio/validator/FormEditorValidatorTest.java index c59ac7cd..c423a19f 100644 --- a/form-editor-studio-lib/src/test/java/com/tallence/formeditor/studio/validator/FormEditorValidatorTest.java +++ b/form-editor-studio-lib/src/test/java/com/tallence/formeditor/studio/validator/FormEditorValidatorTest.java @@ -26,6 +26,7 @@ import com.coremedia.springframework.xml.ResourceAwareXmlBeanDefinitionReader; import com.tallence.formeditor.FormEditorConfiguration; import com.tallence.formeditor.FormEditorHelper; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -35,8 +36,11 @@ import org.springframework.context.annotation.Import; import org.springframework.context.annotation.ImportResource; import org.springframework.context.annotation.Scope; +import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; import java.util.Arrays; import java.util.Collections; @@ -58,6 +62,11 @@ public class FormEditorValidatorTest { @Autowired private FormEditorValidator formEditorValidator; + @Before + public void setUp() { + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(new MockHttpServletRequest())); + } + @Test public void testValidDoc() { Content testContent = contentRepository.getContent("2"); diff --git a/form-editor-studio-lib/src/test/resources/com/tallence/formeditor/studio/validator/FormEditorValidatorTest-content.xml b/form-editor-studio-lib/src/test/resources/com/tallence/formeditor/studio/validator/FormEditorValidatorTest-content.xml index 309b49f1..41eabc5d 100644 --- a/form-editor-studio-lib/src/test/resources/com/tallence/formeditor/studio/validator/FormEditorValidatorTest-content.xml +++ b/form-editor-studio-lib/src/test/resources/com/tallence/formeditor/studio/validator/FormEditorValidatorTest-content.xml @@ -22,6 +22,7 @@ + diff --git a/form-editor-test-util/src/main/resources/com/tallence/formeditor/testdata/20formElements.xml b/form-editor-test-util/src/main/resources/com/tallence/formeditor/testdata/20formElements.xml new file mode 100644 index 00000000..b6a69ccf --- /dev/null +++ b/form-editor-test-util/src/main/resources/com/tallence/formeditor/testdata/20formElements.xml @@ -0,0 +1,81 @@ + + + + + + PageElement + TestPage 1 + DEFAULT_PAGE + + + + + TextArea + SubTextArea + Geben Sie nochmal etwas ein! + 4 + 5 + + + true + 10 + + + + + + + HiddenField + HiddenFieldName + HiddenValue + + + + + + + + + + PageElement + TestPage 2 + SUMMARY_PAGE +

      Description of the page

      + + + + + StreetNumberField + Street and number + + + + + TextOnly + TextOnly + Das ist ein langer Text zur Erklärung des PageTab 2 + + + + + + NumberField + Alter + Geben Sie etwas ein! + + + true + 200 + 5 + + + + + + +
      +
      + +
      +
      +
      diff --git a/form-editor-test-util/src/main/resources/com/tallence/formeditor/testdata/2formElements.xml b/form-editor-test-util/src/main/resources/com/tallence/formeditor/testdata/2formElements.xml index 4694164f..1a9ba2cd 100644 --- a/form-editor-test-util/src/main/resources/com/tallence/formeditor/testdata/2formElements.xml +++ b/form-editor-test-util/src/main/resources/com/tallence/formeditor/testdata/2formElements.xml @@ -380,6 +380,14 @@
      + + + HiddenField + HiddenFieldName + HiddenValue + + + ConsentFormCheckBox diff --git a/form-editor-test-util/src/main/resources/com/tallence/formeditor/testdata/content.xml b/form-editor-test-util/src/main/resources/com/tallence/formeditor/testdata/content.xml index 92cf6b85..71d7a402 100644 --- a/form-editor-test-util/src/main/resources/com/tallence/formeditor/testdata/content.xml +++ b/form-editor-test-util/src/main/resources/com/tallence/formeditor/testdata/content.xml @@ -37,6 +37,14 @@ + + + + + + + + diff --git a/form-editor-test-util/src/main/resources/com/tallence/formeditor/testdata/form-doctypes-xmlrepo.xml b/form-editor-test-util/src/main/resources/com/tallence/formeditor/testdata/form-doctypes-xmlrepo.xml index a32926b3..c2380eeb 100644 --- a/form-editor-test-util/src/main/resources/com/tallence/formeditor/testdata/form-doctypes-xmlrepo.xml +++ b/form-editor-test-util/src/main/resources/com/tallence/formeditor/testdata/form-doctypes-xmlrepo.xml @@ -5,6 +5,7 @@ +