From 29c95a7e650d797f0e29252d26772c2d0f90f56e Mon Sep 17 00:00:00 2001 From: Benjamin Franzke <ben@bnf.dev> Date: Wed, 9 Aug 2023 13:39:16 +0200 Subject: [PATCH] [TASK] Migrate @typo3/form/backend/form-editor to TypeScript Resolves: #101713 Related: #82577 Releases: main, 12.4 Change-Id: Ic7b41b79552a4c14d7395609e0ac3dda9c47b20f Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/80721 Tested-by: core-ci <typo3@b13.com> Tested-by: Benjamin Franzke <ben@bnf.dev> Reviewed-by: Benjamin Franzke <ben@bnf.dev> --- .../TypeScript/form/backend/form-editor.ts | 855 ++++++++++++ .../Sources/TypeScript/form/backend/helper.ts | 15 +- .../Public/JavaScript/backend/form-editor.js | 1157 +---------------- 3 files changed, 861 insertions(+), 1166 deletions(-) create mode 100644 Build/Sources/TypeScript/form/backend/form-editor.ts diff --git a/Build/Sources/TypeScript/form/backend/form-editor.ts b/Build/Sources/TypeScript/form/backend/form-editor.ts new file mode 100644 index 000000000000..ec331a9b090a --- /dev/null +++ b/Build/Sources/TypeScript/form/backend/form-editor.ts @@ -0,0 +1,855 @@ +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +/** + * Module: @typo3/form/backend/form-editor + */ +import $ from 'jquery'; +import Notification from '@typo3/backend/notification'; +import * as Core from '@typo3/form/backend/form-editor/core'; +import type { JavaScriptItemPayload } from '@typo3/core/java-script-item-processor'; +import type { + ApplicationStateStack, + AjaxRequests, + Endpoints, + CollectionElementConfiguration, + CollectionEntry, + DataBackend, + Factory, + FormEditorDefinitions, + FormElement, + FormElementDefinition, + FormElementPropertyValidatorDefinition, + PublisherSubscriber, + PropertyCollectionElement, + PropertyValidationService, + Repository, + RootFormElement, + Utility, + ValidationResults, + ValidationResultsWithPath, + ValidationResultsRecursive, + Validator +} from '@typo3/form/backend/form-editor/core'; + +const assert = Core.assert; + +type AdditionalViewModelModules = JavaScriptItemPayload[]; + +export interface Mediator { + bootstrap(formEditorInstance: FormEditor, viewModel: ViewModel): void; +} + +export interface ViewModel { + bootstrap(formEditorInstance: FormEditor, additionalViewModelModules: AdditionalViewModelModules): void; + enableButton(button: JQuery): void; + disableButton(button: JQuery): void; + hideComponent(component: JQuery): void; + showRemoveFormElementModal(formElement?: FormElement): void; + showRemoveCollectionElementModal(collectionElementIdentifier: string, collectionName: string, formElement?: FormElement): void; + setElementValidationErrorClass(element: JQuery, classIdentifier?: string): void; + removeElementValidationErrorClass(element: JQuery, classIdentifier?: string): void; +} + +export type FormEditorConfiguration = { + prototypeName: string, + endpoints: Endpoints, + formEditorDefinitions: FormEditorDefinitions, + formDefinition: FormElementDefinition, + formPersistenceIdentifier: string, + additionalViewModelModules: AdditionalViewModelModules, + maximumUndoSteps: number +}; + +export class FormEditor { + private isRunning: boolean = false; + private unsavedContent: boolean = false; + private readonly configuration: FormEditorConfiguration; + private readonly mediator: Mediator; + private readonly viewModel: ViewModel; + + public constructor( + configuration: FormEditorConfiguration, + mediator: Mediator, + viewModel: ViewModel + ) { + this.configuration = configuration || {} as FormEditorConfiguration; + this.mediator = mediator; + this.viewModel = viewModel; + } + + public getPublisherSubscriber(): PublisherSubscriber { + return Core.getPublisherSubscriber(); + } + + public undoApplicationState(): void { + this.getApplicationStateStack().incrementCurrentStackPointer(); + } + + public redoApplicationState(): void { + this.getApplicationStateStack().decrementCurrentStackPointer(); + } + + public getMaximalApplicationStates(): number { + return this.getApplicationStateStack().getMaximalStackSize(); + } + + public getCurrentApplicationStates(): number { + return this.getApplicationStateStack().getCurrentStackSize(); + } + + public getCurrentApplicationStatePosition(): number { + return this.getApplicationStateStack().getCurrentStackPointer(); + } + + /** + * @internal + * @throws 1519855175 + */ + public setFormDefinition(formDefinition: FormElementDefinition): void { + assert('object' === $.type(formDefinition), 'Invalid parameter "formDefinition"', 1519855175); + this.getApplicationStateStack().setCurrentState('formDefinition', this.getFactory().createFormElement(formDefinition, undefined, undefined, true)); + } + + /** + * @throws 1475378543 + */ + public getRunningAjaxRequest<T extends keyof AjaxRequests>( + type: keyof AjaxRequests + ): AjaxRequests[T] | null { + assert(this.getUtility().isNonEmptyString(type), 'Invalid parameter "type"', 1475378543); + return Core.getRunningAjaxRequest(type); + } + + public getUtility(): Utility { + return Core.getUtility(); + } + + public assert(test: boolean|(() => boolean), message: string, messageCode: number): void { + this.getUtility().assert(test, message, messageCode); + } + + public buildPropertyPath( + propertyPath: string, + collectionElementIdentifier?: string, + collectionName?: keyof FormEditorDefinitions, + _formElement?: string | FormElement, + allowEmptyReturnValue?: boolean + ): string { + if (this.getUtility().isUndefinedOrNull(_formElement)) { + _formElement = this.getCurrentlySelectedFormElement(); + } + const formElement = this.getRepository().findFormElement(_formElement); + return this.getUtility().buildPropertyPath( + propertyPath, + collectionElementIdentifier, + collectionName, + formElement, + allowEmptyReturnValue + ); + } + + public addPropertyValidationValidator(validatorIdentifier: string, func: Validator): void { + this.getPropertyValidationService().addValidator(validatorIdentifier, func); + } + + public validateCurrentlySelectedFormElementProperty( + propertyPath: string + ): ValidationResults { + return this.validateFormElementProperty( + this.getCurrentlySelectedFormElement(), + propertyPath + ); + } + + public validateFormElementProperty( + _formElement: FormElement | string, + propertyPath: string + ): ValidationResults { + const formElement = this.getRepository().findFormElement(_formElement); + return this.getPropertyValidationService().validateFormElementProperty(formElement, propertyPath); + } + + public validateFormElement( + _formElement: FormElement | string + ): ValidationResultsWithPath { + const formElement = this.getRepository().findFormElement(_formElement); + return this.getPropertyValidationService().validateFormElement(formElement); + } + + public validationResultsHasErrors( + validationResults: ValidationResultsRecursive + ): boolean { + return this.getPropertyValidationService().validationResultsHasErrors(validationResults); + } + + public validateFormElementRecursive( + _formElement: FormElement | string, + returnAfterFirstMatch?: boolean + ): ValidationResultsRecursive { + const formElement = this.getRepository().findFormElement(_formElement); + return this.getPropertyValidationService().validateFormElementRecursive(formElement, returnAfterFirstMatch); + } + + /** + * @throws 1475378544 + */ + public setUnsavedContent(unsavedContent: boolean): void { + assert('boolean' === $.type(unsavedContent), 'Invalid parameter "unsavedContent"', 1475378544); + this.unsavedContent = unsavedContent; + } + + public getUnsavedContent(): boolean { + return this.unsavedContent; + } + + public getRootFormElement(): RootFormElement { + return this.getRepository().getRootFormElement(); + } + + public getCurrentlySelectedFormElement(): FormElement { + return this.getRepository().findFormElementByIdentifierPath(this.getApplicationStateStack().getCurrentState('currentlySelectedFormElementIdentifierPath')); + } + + /** + * @publish core/currentlySelectedFormElementChanged + */ + public setCurrentlySelectedFormElement( + _formElement: FormElement | string, + doNotRefreshCurrentlySelectedPageIndex?: boolean + ): void { + doNotRefreshCurrentlySelectedPageIndex = !!doNotRefreshCurrentlySelectedPageIndex; + + const formElement = this.getRepository().findFormElement(_formElement); + this.getApplicationStateStack().setCurrentState('currentlySelectedFormElementIdentifierPath', formElement.get('__identifierPath')); + + if (!doNotRefreshCurrentlySelectedPageIndex) { + this.refreshCurrentlySelectedPageIndex(); + } + this.getPublisherSubscriber().publish('core/currentlySelectedFormElementChanged', [formElement]); + } + + /** + * @throws 1475378545 + */ + public getFormElementByIdentifierPath(identifierPath: string): FormElement { + assert(this.getUtility().isNonEmptyString(identifierPath), 'Invalid parameter "identifierPath"', 1475378545); + return this.getRepository().findFormElementByIdentifierPath(identifierPath); + } + + public isFormElementIdentifierUsed(formElementIdentifier: string): boolean { + return this.getRepository().isFormElementIdentifierUsed(formElementIdentifier); + } + + public createAndAddFormElement( + formElementType: string, + referenceFormElement?: FormElement | string, + disablePublishersOnSet?: boolean + ): FormElement { + const formElement = this.addFormElement( + this.createFormElement(formElementType, disablePublishersOnSet), + referenceFormElement, + disablePublishersOnSet + ); + formElement.set('renderables', formElement.get('renderables')); + return formElement; + } + + /** + * @throws 1475434337 + */ + public addFormElement( + formElement: FormElement, + _referenceFormElement?: FormElement | string, + disablePublishersOnSet?: boolean + ): FormElement { + this.saveApplicationState(); + + if (this.getUtility().isUndefinedOrNull(_referenceFormElement)) { + _referenceFormElement = this.getCurrentlySelectedFormElement(); + } + const referenceFormElement = this.getRepository().findFormElement(_referenceFormElement); + assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475434337); + return this.getRepository().addFormElement(formElement, referenceFormElement, true, disablePublishersOnSet); + } + + /** + * @throws 1475434336 + * @throws 1475435857 + */ + public createFormElement( + formElementType: string, + disablePublishersOnSet: boolean + ): FormElement { + assert(this.getUtility().isNonEmptyString(formElementType), 'Invalid parameter "formElementType"', 1475434336); + + const identifier = this.getRepository().getNextFreeFormElementIdentifier(formElementType); + const formElementDefinition = this.getFormElementDefinitionByType(formElementType, undefined); + return this.getFactory().createFormElement({ + type: formElementType, + identifier: identifier, + label: formElementDefinition.label || formElementType + }, undefined, undefined, undefined, disablePublishersOnSet); + } + + public removeFormElement( + _formElementToRemove: FormElement | string, + disablePublishersOnSet?: boolean + ): FormElement { + this.saveApplicationState(); + + const formElementToRemove = this.getRepository().findFormElement(_formElementToRemove); + const parentFormElement = formElementToRemove.get('__parentRenderable'); + this.getRepository().removeFormElement(formElementToRemove, true, disablePublishersOnSet); + return parentFormElement; + } + + /** + * @throws 1475378551 + */ + public moveFormElement( + _formElementToMove: FormElement | string, + position: string, + _referenceFormElement: FormElement | string, + disablePublishersOnSet?: boolean + ): FormElement { + this.saveApplicationState(); + + let formElementToMove = this.getRepository().findFormElement(_formElementToMove); + const referenceFormElement = this.getRepository().findFormElement(_referenceFormElement); + + assert('after' === position || 'before' === position || 'inside' === position, 'Invalid position "' + position + '"', 1475378551); + + formElementToMove = this.getRepository().moveFormElement(formElementToMove, position, referenceFormElement, true); + disablePublishersOnSet = !!disablePublishersOnSet; + if (!disablePublishersOnSet) { + formElementToMove.get('__parentRenderable').set('renderables', formElementToMove.get('__parentRenderable').get('renderables')); + } + return formElementToMove; + } + + /** + * @throws 1475378555 + * @throws 1475378556 + * @throws 1475446108 + */ + public getPropertyCollectionElementConfiguration( + collectionElementIdentifier: string, + collectionName: keyof FormEditorDefinitions, + _formElement?: string | FormElement + ): CollectionEntry { + let collection, collectionElement; + if (this.getUtility().isUndefinedOrNull(_formElement)) { + _formElement = this.getCurrentlySelectedFormElement(); + } + const formElement = this.getRepository().findFormElement(_formElement); + + assert(this.getUtility().isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475378555); + assert(this.getUtility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475378556); + + const formElementDefinition = this.getFormElementDefinitionByType(formElement.get('type'), undefined); + if (!this.getUtility().isUndefinedOrNull(formElementDefinition.propertyCollections)) { + collection = formElementDefinition.propertyCollections[collectionName]; + assert(!this.getUtility().isUndefinedOrNull(collection), 'Invalid collection name "' + collectionName + '"', 1475446108); + collectionElement = this.getRepository().findCollectionElementByIdentifierPath(collectionElementIdentifier, collection); + // Return a dereferenced object + return $.extend(true, {}, collectionElement); + } else { + return {} as CollectionEntry; + } + } + + /** + * @throws 1475378557 + * @throws 1475378558 + */ + public getIndexFromPropertyCollectionElement( + collectionElementIdentifier: string, + collectionName: keyof FormEditorDefinitions, + _formElement?: string | FormElement + ): number { + if (this.getUtility().isUndefinedOrNull(_formElement)) { + _formElement = this.getCurrentlySelectedFormElement(); + } + const formElement = this.getRepository().findFormElement(_formElement); + + assert(this.getUtility().isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475378557); + assert(this.getUtility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475378558); + + const indexFromPropertyCollectionElement = this.getRepository().getIndexFromPropertyCollectionElementByIdentifier( + collectionElementIdentifier, + collectionName, + formElement + ); + + return indexFromPropertyCollectionElement; + } + + public createAndAddPropertyCollectionElement( + collectionElementIdentifier: string, + collectionName: keyof FormEditorDefinitions, + formElement: FormElement, + collectionElementConfiguration: CollectionElementConfiguration, + referenceCollectionElementIdentifier: string + ): FormElement { + return this.addPropertyCollectionElement( + this.createPropertyCollectionElement( + collectionElementIdentifier, + collectionName, + collectionElementConfiguration + ), + collectionName, + formElement, + referenceCollectionElementIdentifier + ); + } + + /** + * @throws 1475443300 + * @throws 1475443301 + */ + public addPropertyCollectionElement( + collectionElement: CollectionEntry, + collectionName: keyof FormEditorDefinitions, + _formElement?: FormElement | string, + referenceCollectionElementIdentifier?: string + ): FormElement { + let collection; + this.saveApplicationState(); + + if (this.getUtility().isUndefinedOrNull(_formElement)) { + _formElement = this.getCurrentlySelectedFormElement(); + } + const formElement = this.getRepository().findFormElement(_formElement); + + assert('object' === $.type(collectionElement), 'Invalid parameter "collectionElement"', 1475443301); + assert(this.getUtility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475443300); + + if (this.getUtility().isUndefinedOrNull(referenceCollectionElementIdentifier)) { + collection = formElement.get(collectionName); + if ('array' === $.type(collection) && collection.length > 0) { + referenceCollectionElementIdentifier = collection[collection.length - 1].identifier; + } + } + + return this.getRepository().addPropertyCollectionElement( + collectionElement, + collectionName, + formElement, + referenceCollectionElementIdentifier, + false + ); + } + + /** + * @throws 1475378559 + * @throws 1475378560 + */ + public createPropertyCollectionElement( + collectionElementIdentifier: string, + collectionName: keyof FormEditorDefinitions, + collectionElementConfiguration: CollectionElementConfiguration + ): PropertyCollectionElement { + assert(this.getUtility().isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475378559); + assert(this.getUtility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475378560); + if ('object' !== $.type(collectionElementConfiguration)) { + collectionElementConfiguration = {} as CollectionElementConfiguration; + } + + return this.getFactory().createPropertyCollectionElement( + collectionElementIdentifier, + collectionElementConfiguration, + collectionName + ); + } + + /** + * @throws 1475378561 + * @throws 1475378562 + */ + public removePropertyCollectionElement( + collectionElementIdentifier: string, + collectionName: keyof FormEditorDefinitions, + _formElement?: FormElement | string, + disablePublishersOnSet?: boolean + ): void { + this.saveApplicationState(); + + if (this.getUtility().isUndefinedOrNull(_formElement)) { + _formElement = this.getCurrentlySelectedFormElement(); + } + const formElement = this.getRepository().findFormElement(_formElement); + + assert(this.getUtility().isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475378561); + assert(this.getUtility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475378562); + + this.getRepository().removePropertyCollectionElementByIdentifier( + formElement, + collectionElementIdentifier, + collectionName, + true + ); + + disablePublishersOnSet = !!disablePublishersOnSet; + if (!disablePublishersOnSet) { + this.getPublisherSubscriber().publish('core/formElement/somePropertyChanged', ['__fakeProperty']); + } + } + + /** + * @throws 1477404352 + * @throws 1477404353 + * @throws 1477404354 + * @throws 1477404355 + */ + public movePropertyCollectionElement( + collectionElementToMove: string, + position: string, + referenceCollectionElement: string, + collectionName: keyof FormEditorDefinitions, + formElement: FormElement, + disablePublishersOnSet?: boolean + ): void { + this.saveApplicationState(); + + formElement = this.getRepository().findFormElement(formElement); + + assert('string' === $.type(collectionElementToMove), 'Invalid parameter "collectionElementToMove"', 1477404352); + assert('string' === $.type(referenceCollectionElement), 'Invalid parameter "referenceCollectionElement"', 1477404353); + assert('after' === position || 'before' === position, 'Invalid position "' + position + '"', 1477404354); + assert(this.getUtility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1477404355); + + this.getRepository().movePropertyCollectionElement(collectionElementToMove, position, referenceCollectionElement, collectionName, formElement, disablePublishersOnSet); + } + + /** + * @throws 1475378563 + */ + public getFormElementDefinitionByType<T extends undefined | keyof FormElementDefinition, R = T extends keyof FormElementDefinition ? FormElementDefinition[T] : FormElementDefinition>( + elementType: string, + formElementDefinitionKey?: T + ): R { + assert(this.getUtility().isNonEmptyString(elementType), 'Invalid parameter "elementType"', 1475378563); + + const formElementDefinition = this.getRepository().getFormEditorDefinition('formElements', elementType); + + if (formElementDefinitionKey !== undefined/* && formElementDefinitionKey !== null*/) { + const formElementDefinitionEntry = formElementDefinition[formElementDefinitionKey]; + if (formElementDefinitionEntry !== null && (typeof formElementDefinitionEntry === 'object')) { + return $.extend(true, {}, formElementDefinitionEntry); + } else { + return formElementDefinitionEntry as R; + } + } + + if (formElementDefinition !== null && (typeof formElementDefinition === 'object')) { + return $.extend(true, {}, formElementDefinition); + } else { + return formElementDefinition as R; + } + } + + public getFormElementDefinition<T extends keyof FormElementDefinition>( + formElement: FormElement | string, + formElementDefinitionKey?: T + ): T extends keyof FormElementDefinition ? FormElementDefinition[T] : FormElementDefinition { + formElement = this.getRepository().findFormElement(formElement); + return this.getFormElementDefinitionByType(formElement.get('type'), formElementDefinitionKey); + } + + public getFormEditorDefinition<D extends keyof FormEditorDefinitions, S extends keyof FormEditorDefinitions[D]>( + definitionName: D, + subject: S + ): FormEditorDefinitions[D][S] { + return this.getRepository().getFormEditorDefinition(definitionName, subject); + } + + /** + * @throws 1475672362 + */ + public getFormElementPropertyValidatorDefinition(validatorIdentifier: string): FormElementPropertyValidatorDefinition { + assert(this.getUtility().isNonEmptyString(validatorIdentifier), 'Invalid parameter "validatorIdentifier"', 1475672362); + + const validatorDefinition = this.getRepository().getFormEditorDefinition('formElementPropertyValidators', validatorIdentifier); + // Return a dereferenced object + return $.extend(true, {}, validatorDefinition); + } + + public getCurrentlySelectedPageIndex(): number { + return this.getApplicationStateStack().getCurrentState('currentlySelectedPageIndex'); + } + + public refreshCurrentlySelectedPageIndex(): void { + this.getApplicationStateStack().setCurrentState( + 'currentlySelectedPageIndex', + this.getPageIndexFromFormElement(this.getCurrentlySelectedFormElement()) + ); + } + + /** + * @throws 1477786068 + */ + public getCurrentlySelectedPage(): FormElement { + const currentPage = this.getRepository().getRootFormElement().get('renderables')[this.getCurrentlySelectedPageIndex()]; + assert('object' === $.type(currentPage), 'No page found', 1477786068); + return currentPage; + } + + public getLastTopLevelElementOnCurrentPage(): FormElement { + + const renderables = this.getCurrentlySelectedPage().get('renderables'); + if (this.getUtility().isUndefinedOrNull(renderables)) { + return undefined; + } + return renderables[renderables.length - 1]; + } + + public getLastFormElementWithinParentFormElement(formElement: FormElement): FormElement { + formElement = this.getRepository().findFormElement(formElement); + if (formElement.get('__identifierPath') === this.getRootFormElement().get('__identifierPath')) { + return formElement; + } + return formElement.get('__parentRenderable').get('renderables')[formElement.get('__parentRenderable').get('renderables').length - 1]; + } + + public getPageIndexFromFormElement(formElement: FormElement | string): number { + formElement = this.getRepository().findFormElement(formElement); + + return this.getRepository().getIndexForEnclosingCompositeFormElementWhichIsOnTopLevelForFormElement( + formElement + ); + } + + public renderCurrentFormPage(): void { + this.renderFormPage(this.getCurrentlySelectedPageIndex()); + } + + /** + * @throws 1475446442 + */ + public renderFormPage(pageIndex: number): void { + assert('number' === $.type(pageIndex), 'Invalid parameter "pageIndex"', 1475446442); + this.getDataBackend().renderFormDefinitionPage(pageIndex); + } + + public findEnclosingCompositeFormElementWhichIsNotOnTopLevel( + formElement: FormElement | string + ): FormElement | null { + return this.getRepository().findEnclosingCompositeFormElementWhichIsNotOnTopLevel( + this.getRepository().findFormElement(formElement) + ); + } + + /** + * @todo deprecate, method is unused + */ + public findEnclosingGridRowFormElement( + formElement: FormElement | string + ): FormElement | null { + return this.getRepository().findEnclosingGridRowFormElement( + this.getRepository().findFormElement(formElement) + ); + } + + public getNonCompositeNonToplevelFormElements(): FormElement[] { + return this.getRepository().getNonCompositeNonToplevelFormElements(); + } + + public isRootFormElementSelected(): boolean { + return (this.getCurrentlySelectedFormElement().get('__identifierPath') === this.getRootFormElement().get('__identifierPath')); + } + + public getViewModel(): ViewModel { + return this.viewModel; + } + + public saveFormDefinition(): void { + this.getDataBackend().saveFormDefinition(); + } + + /** + * @throws 1473200696 + */ + public run(): FormEditor { + if (this.isRunning) { + throw 'You can not run the app twice (1473200696)'; + } + + try { + this.bootstrap(); + this.isRunning = true; + } catch(error) { + Notification.error( + TYPO3.lang['formEditor.error.headline'], + TYPO3.lang['formEditor.error.message'] + + '\r\n' + + '\r\n' + + TYPO3.lang['formEditor.error.technicalReason'] + + '\r\n' + + error.message); + } + return this; + } + + private saveApplicationState(): void { + this.getApplicationStateStack().addAndReset({ + formDefinition: this.getApplicationStateStack().getCurrentState('formDefinition').clone(), + currentlySelectedPageIndex: this.getApplicationStateStack().getCurrentState('currentlySelectedPageIndex'), + currentlySelectedFormElementIdentifierPath: this.getApplicationStateStack().getCurrentState('currentlySelectedFormElementIdentifierPath') + }); + } + + private getDataBackend(): DataBackend { + return Core.getDataBackend(); + } + + private getFactory(): Factory { + return Core.getFactory(); + } + + private getRepository(): Repository { + return Core.getRepository(); + } + + private getPropertyValidationService(): PropertyValidationService { + return Core.getPropertyValidationService(); + } + + private getApplicationStateStack(): ApplicationStateStack { + return Core.getApplicationStateStack(); + } + + /** + * @publish ajax/beforeSend + * @publish ajax/complete + */ + private ajaxSetup(): void { + $.ajaxSetup({ + beforeSend: () => { + this.getPublisherSubscriber().publish('ajax/beforeSend'); + }, + complete: () => { + this.getPublisherSubscriber().publish('ajax/complete'); + } + }); + } + + /** + * @throws 1475379748 + * @throws 1475379749 + * @throws 1475927876 + */ + private dataBackendSetup(endpoints: Endpoints, prototypeName: string, formPersistenceIdentifier: string): void { + assert('object' === $.type(endpoints), 'Invalid parameter "endpoints"', 1475379748); + assert(this.getUtility().isNonEmptyString(prototypeName), 'Invalid parameter "prototypeName"', 1475927876); + assert(this.getUtility().isNonEmptyString(formPersistenceIdentifier), 'Invalid parameter "formPersistenceIdentifier"', 1475379749); + + Core.getDataBackend().setEndpoints(endpoints); + Core.getDataBackend().setPrototypeName(prototypeName); + Core.getDataBackend().setPersistenceIdentifier(formPersistenceIdentifier); + } + + /** + * @throws 1475379750 + */ + private repositorySetup(formEditorDefinitions: FormEditorDefinitions): void { + assert('object' === $.type(formEditorDefinitions), 'Invalid parameter "formEditorDefinitions"', 1475379750); + + this.getRepository().setFormEditorDefinitions(formEditorDefinitions); + } + + /** + * @throws 1475492374 + */ + private viewSetup(additionalViewModelModules: AdditionalViewModelModules): void { + assert('function' === $.type(this.viewModel.bootstrap), 'The view model does not implement the method "bootstrap"', 1475492374); + + if (this.getUtility().isUndefinedOrNull(additionalViewModelModules)) { + additionalViewModelModules = []; + } + this.viewModel.bootstrap(formEditorInstance, additionalViewModelModules); + } + + /** + * @throws 1475492032 + */ + private mediatorSetup(): void { + assert('function' === $.type(this.mediator.bootstrap), 'The mediator does not implement the method "bootstrap"', 1475492032); + this.mediator.bootstrap(formEditorInstance, this.viewModel); + } + + /** + * @throws 1475379751 + */ + private applicationStateStackSetup( + rootFormElement: FormElementDefinition, + maximumUndoSteps: number + ): void { + assert('object' === $.type(rootFormElement), 'Invalid parameter "rootFormElement"', 1475379751); + + if ('number' !== $.type(maximumUndoSteps)) { + maximumUndoSteps = 10; + } + this.getApplicationStateStack().setMaximalStackSize(maximumUndoSteps); + + this.getApplicationStateStack().addAndReset({ + currentlySelectedPageIndex: 0, + currentlySelectedFormElementIdentifierPath: rootFormElement.identifier + }, true); + + this.getApplicationStateStack().setCurrentState('formDefinition', this.getFactory().createFormElement(rootFormElement, undefined, undefined, true)); + } + + private bootstrap(): void { + this.mediatorSetup(); + this.ajaxSetup(); + this.dataBackendSetup(this.configuration.endpoints, this.configuration.prototypeName, this.configuration.formPersistenceIdentifier); + this.repositorySetup(this.configuration.formEditorDefinitions); + this.applicationStateStackSetup(this.configuration.formDefinition, this.configuration.maximumUndoSteps); + this.setCurrentlySelectedFormElement(this.getRepository().getRootFormElement()); + + this.viewSetup(this.configuration.additionalViewModelModules); + } +} + +let formEditorInstance: FormEditor = null; + +/** + * @public + * @static + * + * Implement the "Singleton Pattern". + * + * Return a singleton instance of a + * "FormEditor" object. + */ +export function getInstance( + configuration: FormEditorConfiguration, + mediator: Mediator, + viewModel: ViewModel +): FormEditor { + if (formEditorInstance === null) { + formEditorInstance = new FormEditor(configuration, mediator, viewModel); + } + return formEditorInstance; +} + +declare global { + interface PublisherSubscriberTopicArgumentsMap { + 'core/currentlySelectedFormElementChanged': readonly [ + formElement: FormElement + ]; + 'ajax/beforeSend': undefined; + 'ajax/complete': undefined; + } +} diff --git a/Build/Sources/TypeScript/form/backend/helper.ts b/Build/Sources/TypeScript/form/backend/helper.ts index d5ea289a463b..d755679d839b 100644 --- a/Build/Sources/TypeScript/form/backend/helper.ts +++ b/Build/Sources/TypeScript/form/backend/helper.ts @@ -20,15 +20,6 @@ interface ModuleRequirements { mediator?: JavaScriptItemPayload; } -interface FormEditorLike { - getInstance(options: any, mediator: MediatorLike, viewModel: typeof import('@typo3/form/backend/form-manager/view-model')): FormEditorLike; - run(): FormEditorLike; -} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -interface MediatorLike { -} - /** * @exports @typo3/form/backend/helper */ @@ -40,7 +31,11 @@ export class Helper { loadModule(requirements.mediator), loadModule(requirements.viewModel), ]).then((modules: [any, any, any]) => - ((app: FormEditorLike, mediator: MediatorLike, viewModel: typeof import('@typo3/form/backend/form-manager/view-model')) => { + (( + app: typeof import('@typo3/form/backend/form-editor'), + mediator: import('@typo3/form/backend/form-editor').Mediator, + viewModel: import('@typo3/form/backend/form-editor').ViewModel + ) => { window.TYPO3.FORMEDITOR_APP = app.getInstance(options, mediator, viewModel).run(); })(...modules) ); diff --git a/typo3/sysext/form/Resources/Public/JavaScript/backend/form-editor.js b/typo3/sysext/form/Resources/Public/JavaScript/backend/form-editor.js index b58dfd21f75f..9f1fc2d1a8a2 100644 --- a/typo3/sysext/form/Resources/Public/JavaScript/backend/form-editor.js +++ b/typo3/sysext/form/Resources/Public/JavaScript/backend/form-editor.js @@ -10,1159 +10,4 @@ * * The TYPO3 project - inspiring people to share! */ - -/** - * Module: @typo3/form/backend/form-editor - */ -import $ from 'jquery'; -import * as Core from '@typo3/form/backend/form-editor/core.js'; -import Notification from '@typo3/backend/notification.js'; - -const { - getInstance -} = factory($, Core, Notification); - -export { - getInstance -}; - -function factory($, core, Notification) { - /** - * Return a static method named "getInstance". - * Use this method to create the formeditor app. - */ - return (function(_core, Notification) { - - /** - * @private - * - * Hold the instance (Singleton Pattern) - */ - var _formEditorInstance = null; - - /** - * @public - * - * @param object _configuration - * @param object _mediator - * @param object _viewModel - * @return object - */ - function FormEditor(_configuration, _mediator, _viewModel) { - - /** - * @private - * - * @var bool - */ - var _isRunning = false; - - /** - * @private - * - * @var bool - */ - var _unsavedContent = false; - - /** - * @private - * - * @var bool - */ - var _previewMode = false; - - /** - * @public - * - * @return object - */ - function getPublisherSubscriber() { - return _core.getPublisherSubscriber(); - }; - - /** - * @public - * - * @return void - */ - function _saveApplicationState() { - - _getApplicationStateStack().addAndReset({ - formDefinition: _getApplicationStateStack().getCurrentState('formDefinition').clone(), - currentlySelectedPageIndex: _getApplicationStateStack().getCurrentState('currentlySelectedPageIndex'), - currentlySelectedFormElementIdentifierPath: _getApplicationStateStack().getCurrentState('currentlySelectedFormElementIdentifierPath') - }); - }; - - /** - * @public - * - * @return void - */ - function undoApplicationState() { - _getApplicationStateStack().incrementCurrentStackPointer(); - }; - - /** - * @public - * - * @return void - */ - function redoApplicationState() { - _getApplicationStateStack().decrementCurrentStackPointer(); - }; - - /** - * @public - * - * @return int - */ - function getMaximalApplicationStates() { - return _getApplicationStateStack().getMaximalStackSize(); - }; - - /** - * @public - * - * @return int - */ - function getCurrentApplicationStates() { - return _getApplicationStateStack().getCurrentStackSize(); - }; - - /** - * @public - * - * @return int - */ - function getCurrentApplicationStatePosition() { - return _getApplicationStateStack().getCurrentStackPointer(); - }; - - /** - * @internal - * - * @return void - * @throws 1519855175 - */ - function setFormDefinition(formDefinition) { - assert('object' === $.type(formDefinition), 'Invalid parameter "formDefinition"', 1519855175); - _getApplicationStateStack().setCurrentState('formDefinition', _getFactory().createFormElement(formDefinition, undefined, undefined, true)); - }; - - /** - * @public - * - * @param string type - * @return object - * @throws 1475378543 - */ - function getRunningAjaxRequest(type) { - assert(getUtility().isNonEmptyString(type), 'Invalid parameter "type"', 1475378543); - return _core.getRunningAjaxRequest(type); - }; - - /** - * @public - * - * @return object - */ - function getUtility() { - return _core.getUtility(); - }; - - /** - * @public - * - * @param mixed test - * @param string message - * @param int messageCode - * @return void - */ - function assert(test, message, messageCode) { - getUtility().assert(test, message, messageCode); - }; - - /** - * @public - * - * @param string propertyPath - * @param string collectionElementIdentifier - * @param string collectionName - * @param object formElement - * @param boolean allowEmptyReturnValue - * @return string - */ - function buildPropertyPath(propertyPath, collectionElementIdentifier, collectionName, formElement, allowEmptyReturnValue) { - if (getUtility().isUndefinedOrNull(formElement)) { - formElement = getCurrentlySelectedFormElement(); - } - formElement = _getRepository().findFormElement(formElement); - return getUtility().buildPropertyPath(propertyPath, collectionElementIdentifier, collectionName, formElement, allowEmptyReturnValue); - }; - - /** - * @public - * - * @param string validatorIdentifier - * @param function func - * @return void - */ - function addPropertyValidationValidator(validatorIdentifier, func) { - _getPropertyValidationService().addValidator(validatorIdentifier, func); - }; - - /** - * @public - * - * @param string propertyPath - * @return object - */ - function validateCurrentlySelectedFormElementProperty(propertyPath) { - return validateFormElementProperty( - getCurrentlySelectedFormElement(), - propertyPath - ); - }; - - /** - * @public - * - * @param object formElement - * @param string propertyPath - * @return object - */ - function validateFormElementProperty(formElement, propertyPath) { - formElement = _getRepository().findFormElement(formElement); - return _getPropertyValidationService().validateFormElementProperty(formElement, propertyPath); - }; - - /** - * @public - * - * @param object formElement - * @return object - */ - function validateFormElement(formElement) { - formElement = _getRepository().findFormElement(formElement); - return _getPropertyValidationService().validateFormElement(formElement); - }; - - /** - * @public - * - * @param object validationResults - * @return boolean - */ - function validationResultsHasErrors(validationResults) { - return _getPropertyValidationService().validationResultsHasErrors(validationResults); - }; - - /** - * @public - * - * @param object formElement - * @param boolean returnAfterFirstMatch - * @return object - */ - function validateFormElementRecursive(formElement, returnAfterFirstMatch) { - formElement = _getRepository().findFormElement(formElement); - return _getPropertyValidationService().validateFormElementRecursive(formElement, returnAfterFirstMatch); - }; - - /** - * @public - * - * @param bool unsavedContent - * @return void - * @throws 1475378544 - */ - function setUnsavedContent(unsavedContent) { - assert('boolean' === $.type(unsavedContent), 'Invalid parameter "unsavedContent"', 1475378544); - _unsavedContent = unsavedContent; - }; - - /** - * @public - * - * @return boolean - */ - function getUnsavedContent() { - return _unsavedContent; - }; - - /** - * @public - * - * @return object - */ - function getRootFormElement() { - return _getRepository().getRootFormElement(); - }; - - /** - * @public - * - * @return string - */ - function getCurrentlySelectedFormElement() { - return _getRepository().findFormElementByIdentifierPath(_getApplicationStateStack().getCurrentState('currentlySelectedFormElementIdentifierPath')); - }; - - /** - * @public - * - * @param string|object formElement - * @param boolean doNotRefreshCurrentlySelectedPageIndex - * @return void - * @publish core/currentlySelectedFormElementChanged - */ - function setCurrentlySelectedFormElement(formElement, doNotRefreshCurrentlySelectedPageIndex) { - doNotRefreshCurrentlySelectedPageIndex = !!doNotRefreshCurrentlySelectedPageIndex; - - formElement = _getRepository().findFormElement(formElement); - _getApplicationStateStack().setCurrentState('currentlySelectedFormElementIdentifierPath', formElement.get('__identifierPath')); - - if (!doNotRefreshCurrentlySelectedPageIndex) { - refreshCurrentlySelectedPageIndex(); - } - getPublisherSubscriber().publish('core/currentlySelectedFormElementChanged', [formElement]); - }; - - /** - * @public - * - * @param string identifierPath - * @return object - * @throws 1475378545 - */ - function getFormElementByIdentifierPath(identifierPath) { - assert(getUtility().isNonEmptyString(identifierPath), 'Invalid parameter "identifierPath"', 1475378545); - return _getRepository().findFormElementByIdentifierPath(identifierPath); - }; - - /** - * @public - * - * @param string identifierPath - * @return bool - */ - function isFormElementIdentifierUsed(formElementIdentifier) { - return _getRepository().isFormElementIdentifierUsed(formElementIdentifier); - } - - /** - * @public - * - * @param string formElementType - * @param string|object referenceFormElement - * @param boolean disablePublishersOnSet - * @return object - */ - function createAndAddFormElement(formElementType, referenceFormElement, disablePublishersOnSet) { - var formElement; - formElement = addFormElement(createFormElement(formElementType, disablePublishersOnSet), referenceFormElement, disablePublishersOnSet); - formElement.set('renderables', formElement.get('renderables')); - return formElement; - }; - - /** - * @public - * - * @param object formElement - * @param string|object referenceFormElement - * @param boolean disablePublishersOnSet - * @return object - * @throws 1475434337 - */ - function addFormElement(formElement, referenceFormElement, disablePublishersOnSet) { - _saveApplicationState(); - - if (getUtility().isUndefinedOrNull(referenceFormElement)) { - referenceFormElement = getCurrentlySelectedFormElement(); - } - referenceFormElement = _getRepository().findFormElement(referenceFormElement); - assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475434337); - return _getRepository().addFormElement(formElement, referenceFormElement, true, disablePublishersOnSet); - }; - - /** - * @public - * - * @param string formElementType - * @param boolean disablePublishersOnSet - * @return object - * @throws 1475434336 - * @throws 1475435857 - */ - function createFormElement(formElementType, disablePublishersOnSet) { - var formElementDefinition, identifier; - assert(getUtility().isNonEmptyString(formElementType), 'Invalid parameter "formElementType"', 1475434336); - - identifier = _getRepository().getNextFreeFormElementIdentifier(formElementType); - formElementDefinition = getFormElementDefinitionByType(formElementType); - return _getFactory().createFormElement({ - type: formElementType, - identifier: identifier, - label: formElementDefinition['label'] || formElementType - }, undefined, undefined, undefined, disablePublishersOnSet); - }; - - /** - * @public - * - * @param string|object formElementToRemove - * @param boolean disablePublishersOnSet - * @return object - */ - function removeFormElement(formElementToRemove, disablePublishersOnSet) { - var parentFormElement; - _saveApplicationState(); - - formElementToRemove = _getRepository().findFormElement(formElementToRemove); - parentFormElement = formElementToRemove.get('__parentRenderable'); - _getRepository().removeFormElement(formElementToRemove, true, disablePublishersOnSet); - return parentFormElement; - }; - - /** - * @public - * - * @param string|object formElementToMove - * @param string position - * @param string|object referenceFormElement - * @param boolean disablePublishersOnSet - * @return string - * @throws 1475378551 - */ - function moveFormElement(formElementToMove, position, referenceFormElement, disablePublishersOnSet) { - _saveApplicationState(); - - formElementToMove = _getRepository().findFormElement(formElementToMove); - referenceFormElement = _getRepository().findFormElement(referenceFormElement); - - assert('after' === position || 'before' === position || 'inside' === position, 'Invalid position "' + position + '"', 1475378551); - - formElementToMove = _getRepository().moveFormElement(formElementToMove, position, referenceFormElement, true); - disablePublishersOnSet = !!disablePublishersOnSet; - if (!disablePublishersOnSet) { - formElementToMove.get('__parentRenderable').set('renderables', formElementToMove.get('__parentRenderable').get('renderables')); - } - return formElementToMove; - }; - - /** - * @public - * - * @param string collectionElementIdentifier - * @param string collectionName - * @param string formElement - * @return object (dereferenced) - * @throws 1475378555 - * @throws 1475378556 - * @throws 1475446108 - */ - function getPropertyCollectionElementConfiguration(collectionElementIdentifier, collectionName, formElement) { - var collection, collectionElement, formElementDefinition; - if (getUtility().isUndefinedOrNull(formElement)) { - formElement = getCurrentlySelectedFormElement(); - } - formElement = _getRepository().findFormElement(formElement); - - assert(getUtility().isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475378555); - assert(getUtility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475378556); - - formElementDefinition = getFormElementDefinitionByType(formElement.get('type')); - if (!getUtility().isUndefinedOrNull(formElementDefinition['propertyCollections'])) { - collection = formElementDefinition['propertyCollections'][collectionName]; - assert(!getUtility().isUndefinedOrNull(collection), 'Invalid collection name "' + collectionName + '"', 1475446108); - collectionElement = _getRepository().findCollectionElementByIdentifierPath(collectionElementIdentifier, collection); - return $.extend(true, {}, collectionElement); - } else { - return {}; - } - }; - - /** - * @public - * - * @param string collectionElementIdentifier - * @param string collectionName - * @param string formElement - * @return int - * @throws 1475378557 - * @throws 1475378558 - */ - function getIndexFromPropertyCollectionElement(collectionElementIdentifier, collectionName, formElement) { - var indexFromPropertyCollectionElement; - if (getUtility().isUndefinedOrNull(formElement)) { - formElement = getCurrentlySelectedFormElement(); - } - formElement = _getRepository().findFormElement(formElement); - - assert(getUtility().isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475378557); - assert(getUtility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475378558); - - indexFromPropertyCollectionElement = _getRepository().getIndexFromPropertyCollectionElementByIdentifier( - collectionElementIdentifier, - collectionName, - formElement - ); - - return indexFromPropertyCollectionElement; - }; - - /** - * @public - * - * @param string collectionElementIdentifier - * @param string collectionName - * @param object formElement - * @param object collectionElementConfiguration - * @param string referenceCollectionElementIdentifier - * @return object - */ - function createAndAddPropertyCollectionElement(collectionElementIdentifier, collectionName, formElement, collectionElementConfiguration, referenceCollectionElementIdentifier) { - return addPropertyCollectionElement(createPropertyCollectionElement(collectionElementIdentifier, collectionName, collectionElementConfiguration), collectionName, formElement, referenceCollectionElementIdentifier); - }; - - /** - * @public - * - * @param object collectionElement - * @param string collectionName - * @param string|object formElement - * @param string referenceCollectionElementIdentifier - * @return object - * @throws 1475443300 - * @throws 1475443301 - */ - function addPropertyCollectionElement(collectionElement, collectionName, formElement, referenceCollectionElementIdentifier) { - var collection; - _saveApplicationState(); - - if (getUtility().isUndefinedOrNull(formElement)) { - formElement = getCurrentlySelectedFormElement(); - } - formElement = _getRepository().findFormElement(formElement); - - assert('object' === $.type(collectionElement), 'Invalid parameter "collectionElement"', 1475443301); - assert(getUtility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475443300); - - if (getUtility().isUndefinedOrNull(referenceCollectionElementIdentifier)) { - collection = formElement.get(collectionName); - if ('array' === $.type(collection) && collection.length > 0) { - referenceCollectionElementIdentifier = collection[collection.length - 1]['identifier']; - } - } - - return _getRepository().addPropertyCollectionElement( - collectionElement, - collectionName, - formElement, - referenceCollectionElementIdentifier, - false - ); - }; - - /** - * @public - * - * @param string collectionElementIdentifier - * @param string collectionName - * @param object collectionElementConfiguration - * @return void - * @throws 1475378559 - * @throws 1475378560 - */ - function createPropertyCollectionElement(collectionElementIdentifier, collectionName, collectionElementConfiguration) { - assert(getUtility().isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475378559); - assert(getUtility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475378560); - if ('object' !== $.type(collectionElementConfiguration)) { - collectionElementConfiguration = {}; - } - - return _getFactory().createPropertyCollectionElement(collectionElementIdentifier, collectionElementConfiguration, collectionName); - }; - - /** - * @public - * - * @param string collectionElementIdentifier - * @param string collectionName - * @param string formElement - * @param bool disablePublishersOnSet - * @return void - * @throws 1475378561 - * @throws 1475378562 - */ - function removePropertyCollectionElement(collectionElementIdentifier, collectionName, formElement, disablePublishersOnSet) { - _saveApplicationState(); - - if (getUtility().isUndefinedOrNull(formElement)) { - formElement = getCurrentlySelectedFormElement(); - } - formElement = _getRepository().findFormElement(formElement); - - assert(getUtility().isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475378561); - assert(getUtility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475378562); - - _getRepository().removePropertyCollectionElementByIdentifier( - formElement, - collectionElementIdentifier, - collectionName, - true - ); - - disablePublishersOnSet = !!disablePublishersOnSet; - if (!disablePublishersOnSet) { - getPublisherSubscriber().publish('core/formElement/somePropertyChanged', ['__fakeProperty']); - } - }; - - /** - * @public - * - * @param string collectionElementToMove - * @param string position - * @param string referenceCollectionElement - * @param string collectionName - * @param object formElement - * @param boolean disablePublishersOnSet - * @return string - * @throws 1477404352 - * @throws 1477404353 - * @throws 1477404354 - * @throws 1477404355 - */ - function movePropertyCollectionElement(collectionElementToMove, position, referenceCollectionElement, collectionName, formElement, disablePublishersOnSet) { - _saveApplicationState(); - - formElement = _getRepository().findFormElement(formElement); - - assert('string' === $.type(collectionElementToMove), 'Invalid parameter "collectionElementToMove"', 1477404352); - assert('string' === $.type(referenceCollectionElement), 'Invalid parameter "referenceCollectionElement"', 1477404353); - assert('after' === position || 'before' === position, 'Invalid position "' + position + '"', 1477404354); - assert(getUtility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1477404355); - - return _getRepository().movePropertyCollectionElement(collectionElementToMove, position, referenceCollectionElement, collectionName, formElement, disablePublishersOnSet); - }; - - /** - * @public - * - * @param string elementType - * @param string formElementDefinitionKey - * @returnmixed - * @throws 1475378563 - */ - function getFormElementDefinitionByType(elementType, formElementDefinitionKey) { - var formElementDefinition; - assert(getUtility().isNonEmptyString(elementType), 'Invalid parameter "elementType"', 1475378563); - - formElementDefinition = _getRepository().getFormEditorDefinition('formElements', elementType); - - if (!getUtility().isUndefinedOrNull(formElementDefinitionKey)) { - formElementDefinition = formElementDefinition[formElementDefinitionKey]; - } - - if ('object' === $.type(formElementDefinition) || 'array' === $.type(formElementDefinition)) { - return $.extend(true, {}, formElementDefinition); - } else { - return formElementDefinition; - } - }; - - /** - * @public - * - * @param object formElement - * @param string formElementDefinitionKey - * @return mixed - */ - function getFormElementDefinition(formElement, formElementDefinitionKey) { - formElement = _getRepository().findFormElement(formElement); - return getFormElementDefinitionByType(formElement.get('type'), formElementDefinitionKey); - }; - - /** - * @public - * - * @param string collectionName - * @param string collectionElementIdentifier - * @return mixed - */ - function getFormEditorDefinition(definitionName, subject) { - return _getRepository().getFormEditorDefinition(definitionName, subject); - }; - - /** - * @public - * - * @param string validatorIdentifier - * @return object (dereferenced) - * @throws 1475672362 - */ - function getFormElementPropertyValidatorDefinition(validatorIdentifier) { - var validatorDefinition; - assert(getUtility().isNonEmptyString(validatorIdentifier), 'Invalid parameter "validatorIdentifier"', 1475672362); - - validatorDefinition = _getRepository().getFormEditorDefinition('formElementPropertyValidators', validatorIdentifier); - return $.extend(true, {}, validatorDefinition); - }; - - /** - * @public - * - * @return int - */ - function getCurrentlySelectedPageIndex() { - return _getApplicationStateStack().getCurrentState('currentlySelectedPageIndex'); - }; - - /** - * @public - * - * @return void - */ - function refreshCurrentlySelectedPageIndex() { - _getApplicationStateStack().setCurrentState('currentlySelectedPageIndex', getPageIndexFromFormElement(getCurrentlySelectedFormElement())); - }; - - /** - * @public - * - * @return object - * @throws 1477786068 - */ - function getCurrentlySelectedPage() { - var currentPage; - - currentPage = _getRepository().getRootFormElement().get('renderables')[getCurrentlySelectedPageIndex()]; - assert('object' === $.type(currentPage), 'No page found', 1477786068); - return currentPage; - }; - - /** - * @public - * - * @return object - */ - function getLastTopLevelElementOnCurrentPage() { - var lastRenderable, renderables; - - renderables = getCurrentlySelectedPage().get('renderables'); - if (getUtility().isUndefinedOrNull(renderables)) { - return undefined; - } - lastRenderable = renderables[renderables.length - 1]; - return lastRenderable; - }; - - /** - * @public - * - * @param object - * @return object - */ - function getLastFormElementWithinParentFormElement(formElement) { - var lastElement; - - formElement = _getRepository().findFormElement(formElement); - if (formElement.get('__identifierPath') === getRootFormElement().get('__identifierPath')) { - return formElement; - } - return formElement.get('__parentRenderable').get('renderables')[formElement.get('__parentRenderable').get('renderables').length - 1]; - }; - - /** - * @public - * - * @param object - * @return int - */ - function getPageIndexFromFormElement(formElement) { - formElement = _getRepository().findFormElement(formElement); - - return _getRepository().getIndexForEnclosingCompositeFormElementWhichIsOnTopLevelForFormElement( - formElement - ); - }; - - /** - * @public - * - * @return void - */ - function renderCurrentFormPage() { - renderFormPage(getCurrentlySelectedPageIndex()); - }; - - /** - * @public - * - * @param int pageIndex - * @return void - * @throws 1475446442 - */ - function renderFormPage(pageIndex) { - assert('number' === $.type(pageIndex), 'Invalid parameter "pageIndex"', 1475446442); - _getDataBackend().renderFormDefinitionPage(pageIndex); - }; - - /** - * @public - * - * @param object formElement - * @return object|null - */ - function findEnclosingCompositeFormElementWhichIsNotOnTopLevel(formElement) { - return _getRepository().findEnclosingCompositeFormElementWhichIsNotOnTopLevel( - _getRepository().findFormElement(formElement) - ); - }; - - /** - * @public - * - * @param object formElement - * @return object|null - */ - function findEnclosingGridRowFormElement(formElement) { - return _getRepository().findEnclosingGridRowFormElement( - _getRepository().findFormElement(formElement) - ); - }; - - /** - * @public - * - * @return object - */ - function getNonCompositeNonToplevelFormElements() { - return _getRepository().getNonCompositeNonToplevelFormElements(); - }; - - /** - * @public - * - * @return boolean - */ - function isRootFormElementSelected() { - return (getCurrentlySelectedFormElement().get('__identifierPath') === getRootFormElement().get('__identifierPath')); - }; - - /** - * @public - * - * @return object - */ - function getViewModel() { - return _viewModel; - }; - - /** - * @public - * - * @return void - */ - function saveFormDefinition() { - _getDataBackend().saveFormDefinition(); - }; - - /** - * @private - * - * @return object - */ - function _getDataBackend() { - return _core.getDataBackend(); - }; - - /** - * @private - * - * @return object - */ - function _getFactory() { - return _core.getFactory(); - }; - - /** - * @private - * - * @return object - */ - function _getRepository() { - return _core.getRepository(); - }; - - /** - * @private - * - * @return object - */ - function _getPropertyValidationService() { - return _core.getPropertyValidationService(); - }; - - /** - * @public - * - * @return object - */ - function _getApplicationStateStack() { - return _core.getApplicationStateStack(); - }; - - /** - * @private - * - * @return void - * @publish ajax/beforeSend - * @publish ajax/complete - */ - function _ajaxSetup() { - $.ajaxSetup({ - beforeSend: function() { - getPublisherSubscriber().publish('ajax/beforeSend'); - }, - complete: function() { - getPublisherSubscriber().publish('ajax/complete'); - } - }); - }; - - /** - * @private - * - * @param object endpoints - * @param string prototypeName - * @param string formPersistenceIdentifier - * @return void - * @throws 1475379748 - * @throws 1475379749 - * @throws 1475927876 - */ - function _dataBackendSetup(endpoints, prototypeName, formPersistenceIdentifier) { - assert('object' === $.type(endpoints), 'Invalid parameter "endpoints"', 1475379748); - assert(getUtility().isNonEmptyString(prototypeName), 'Invalid parameter "prototypeName"', 1475927876); - assert(getUtility().isNonEmptyString(formPersistenceIdentifier), 'Invalid parameter "formPersistenceIdentifier"', 1475379749); - - _core.getDataBackend().setEndpoints(endpoints); - _core.getDataBackend().setPrototypeName(prototypeName); - _core.getDataBackend().setPersistenceIdentifier(formPersistenceIdentifier); - }; - - /** - * @private - * - * @param object formEditorDefinitions - * @return void - * @throws 1475379750 - */ - function _repositorySetup(formEditorDefinitions) { - assert('object' === $.type(formEditorDefinitions), 'Invalid parameter "formEditorDefinitions"', 1475379750); - - _getRepository().setFormEditorDefinitions(formEditorDefinitions); - } - - /** - * @private - * - * @param object additionalViewModelModules - * @return void - * @throws 1475492374 - */ - function _viewSetup(additionalViewModelModules) { - assert('function' === $.type(_viewModel.bootstrap), 'The view model does not implement the method "bootstrap"', 1475492374); - - if (getUtility().isUndefinedOrNull(additionalViewModelModules)) { - additionalViewModelModules = []; - } - _viewModel.bootstrap(_formEditorInstance, additionalViewModelModules); - }; - - /** - * @private - * - * @return void - * @throws 1475492032 - */ - function _mediatorSetup() { - assert('function' === $.type(_mediator.bootstrap), 'The mediator does not implement the method "bootstrap"', 1475492032); - _mediator.bootstrap(_formEditorInstance, _viewModel); - }; - - /** - * @private - * - * @param object rootFormElement - * @param int maximumUndoSteps - * @return void - * @throws 1475379751 - */ - function _applicationStateStackSetup(rootFormElement, maximumUndoSteps) { - assert('object' === $.type(rootFormElement), 'Invalid parameter "rootFormElement"', 1475379751); - - if ('number' !== $.type(maximumUndoSteps)) { - maximumUndoSteps = 10; - } - _getApplicationStateStack().setMaximalStackSize(maximumUndoSteps); - - _getApplicationStateStack().addAndReset({ - currentlySelectedPageIndex: 0, - currentlySelectedFormElementIdentifierPath: rootFormElement['identifier'] - }, true); - - _getApplicationStateStack().setCurrentState('formDefinition', _getFactory().createFormElement(rootFormElement, undefined, undefined, true)); - }; - - /** - * @private - * - * @return void - */ - function _bootstrap() { - _configuration = _configuration || {}; - - _mediatorSetup(); - _ajaxSetup(); - _dataBackendSetup(_configuration['endpoints'], _configuration['prototypeName'], _configuration['formPersistenceIdentifier']); - _repositorySetup(_configuration['formEditorDefinitions']); - _applicationStateStackSetup(_configuration['formDefinition'], _configuration['maximumUndoSteps']); - setCurrentlySelectedFormElement(_getRepository().getRootFormElement()); - - _viewSetup(_configuration['additionalViewModelModules']); - }; - - /** - * @public - * - * @return TYPO3/CMS/Form/Backend/FormEditor - * @throws 1473200696 - */ - function run() { - if (_isRunning) { - throw 'You can not run the app twice (1473200696)'; - } - - try { - _bootstrap(); - _isRunning = true; - } catch(error) { - Notification.error( - TYPO3.lang['formEditor.error.headline'], - TYPO3.lang['formEditor.error.message'] - + "\r\n" - + "\r\n" - + TYPO3.lang['formEditor.error.technicalReason'] - + "\r\n" - + error.message); - } - return this; - }; - - /** - * Publish the public methods. - * Implements the "Revealing Module Pattern". - */ - return { - getRootFormElement: getRootFormElement, - - createAndAddFormElement: createAndAddFormElement, - createFormElement: createFormElement, - addFormElement: addFormElement, - moveFormElement: moveFormElement, - removeFormElement: removeFormElement, - - getCurrentlySelectedFormElement: getCurrentlySelectedFormElement, - setCurrentlySelectedFormElement: setCurrentlySelectedFormElement, - - getFormElementByIdentifierPath: getFormElementByIdentifierPath, - isFormElementIdentifierUsed: isFormElementIdentifierUsed, - - createAndAddPropertyCollectionElement: createAndAddPropertyCollectionElement, - createPropertyCollectionElement: createPropertyCollectionElement, - addPropertyCollectionElement: addPropertyCollectionElement, - removePropertyCollectionElement: removePropertyCollectionElement, - movePropertyCollectionElement: movePropertyCollectionElement, - getIndexFromPropertyCollectionElement: getIndexFromPropertyCollectionElement, - getPropertyCollectionElementConfiguration: getPropertyCollectionElementConfiguration, - - saveFormDefinition: saveFormDefinition, - renderCurrentFormPage: renderCurrentFormPage, - renderFormPage: renderFormPage, - - getCurrentlySelectedPageIndex: getCurrentlySelectedPageIndex, - refreshCurrentlySelectedPageIndex: refreshCurrentlySelectedPageIndex, - getPageIndexFromFormElement: getPageIndexFromFormElement, - getCurrentlySelectedPage: getCurrentlySelectedPage, - getLastTopLevelElementOnCurrentPage: getLastTopLevelElementOnCurrentPage, - findEnclosingCompositeFormElementWhichIsNotOnTopLevel: findEnclosingCompositeFormElementWhichIsNotOnTopLevel, - findEnclosingGridRowFormElement: findEnclosingGridRowFormElement, - isRootFormElementSelected: isRootFormElementSelected, - getLastFormElementWithinParentFormElement: getLastFormElementWithinParentFormElement, - getNonCompositeNonToplevelFormElements: getNonCompositeNonToplevelFormElements, - - getFormElementDefinitionByType: getFormElementDefinitionByType, - getFormElementDefinition: getFormElementDefinition, - getFormElementPropertyValidatorDefinition: getFormElementPropertyValidatorDefinition, - getFormEditorDefinition: getFormEditorDefinition, - - getPublisherSubscriber: getPublisherSubscriber, - getRunningAjaxRequest: getRunningAjaxRequest, - - setUnsavedContent: setUnsavedContent, - getUnsavedContent: getUnsavedContent, - - addPropertyValidationValidator: addPropertyValidationValidator, - validateFormElementProperty: validateFormElementProperty, - validateCurrentlySelectedFormElementProperty: validateCurrentlySelectedFormElementProperty, - validateFormElement: validateFormElement, - validateFormElementRecursive: validateFormElementRecursive, - validationResultsHasErrors: validationResultsHasErrors, - - getUtility: getUtility, - assert: assert, - buildPropertyPath: buildPropertyPath, - - getViewModel: getViewModel, - undoApplicationState: undoApplicationState, - redoApplicationState: redoApplicationState, - getMaximalApplicationStates: getMaximalApplicationStates, - getCurrentApplicationStates: getCurrentApplicationStates, - getCurrentApplicationStatePosition: getCurrentApplicationStatePosition, - setFormDefinition: setFormDefinition, - - run: run - }; - }; - - /** - * Emulation of static methods - */ - return { - /** - * @public - * @static - * - * Implement the "Singleton Pattern". - * - * Return a singleton instance of a - * "FormEditor" object. - * - * @param object configuration - * @param object mediator - * @param object viewModel - * @return object - */ - getInstance: function(configuration, mediator, viewModel) { - if (_formEditorInstance === null) { - _formEditorInstance = new FormEditor(configuration, mediator, viewModel); - } - return _formEditorInstance; - } - }; - })(core, Notification); -} +import $ from"jquery";import Notification from"@typo3/backend/notification.js";import*as Core from"@typo3/form/backend/form-editor/core.js";const assert=Core.assert;export class FormEditor{constructor(e,t,i){this.isRunning=!1,this.unsavedContent=!1,this.configuration=e||{},this.mediator=t,this.viewModel=i}getPublisherSubscriber(){return Core.getPublisherSubscriber()}undoApplicationState(){this.getApplicationStateStack().incrementCurrentStackPointer()}redoApplicationState(){this.getApplicationStateStack().decrementCurrentStackPointer()}getMaximalApplicationStates(){return this.getApplicationStateStack().getMaximalStackSize()}getCurrentApplicationStates(){return this.getApplicationStateStack().getCurrentStackSize()}getCurrentApplicationStatePosition(){return this.getApplicationStateStack().getCurrentStackPointer()}setFormDefinition(e){assert("object"===$.type(e),'Invalid parameter "formDefinition"',1519855175),this.getApplicationStateStack().setCurrentState("formDefinition",this.getFactory().createFormElement(e,void 0,void 0,!0))}getRunningAjaxRequest(e){return assert(this.getUtility().isNonEmptyString(e),'Invalid parameter "type"',1475378543),Core.getRunningAjaxRequest(e)}getUtility(){return Core.getUtility()}assert(e,t,i){this.getUtility().assert(e,t,i)}buildPropertyPath(e,t,i,r,n){this.getUtility().isUndefinedOrNull(r)&&(r=this.getCurrentlySelectedFormElement());const o=this.getRepository().findFormElement(r);return this.getUtility().buildPropertyPath(e,t,i,o,n)}addPropertyValidationValidator(e,t){this.getPropertyValidationService().addValidator(e,t)}validateCurrentlySelectedFormElementProperty(e){return this.validateFormElementProperty(this.getCurrentlySelectedFormElement(),e)}validateFormElementProperty(e,t){const i=this.getRepository().findFormElement(e);return this.getPropertyValidationService().validateFormElementProperty(i,t)}validateFormElement(e){const t=this.getRepository().findFormElement(e);return this.getPropertyValidationService().validateFormElement(t)}validationResultsHasErrors(e){return this.getPropertyValidationService().validationResultsHasErrors(e)}validateFormElementRecursive(e,t){const i=this.getRepository().findFormElement(e);return this.getPropertyValidationService().validateFormElementRecursive(i,t)}setUnsavedContent(e){assert("boolean"===$.type(e),'Invalid parameter "unsavedContent"',1475378544),this.unsavedContent=e}getUnsavedContent(){return this.unsavedContent}getRootFormElement(){return this.getRepository().getRootFormElement()}getCurrentlySelectedFormElement(){return this.getRepository().findFormElementByIdentifierPath(this.getApplicationStateStack().getCurrentState("currentlySelectedFormElementIdentifierPath"))}setCurrentlySelectedFormElement(e,t){t=!!t;const i=this.getRepository().findFormElement(e);this.getApplicationStateStack().setCurrentState("currentlySelectedFormElementIdentifierPath",i.get("__identifierPath")),t||this.refreshCurrentlySelectedPageIndex(),this.getPublisherSubscriber().publish("core/currentlySelectedFormElementChanged",[i])}getFormElementByIdentifierPath(e){return assert(this.getUtility().isNonEmptyString(e),'Invalid parameter "identifierPath"',1475378545),this.getRepository().findFormElementByIdentifierPath(e)}isFormElementIdentifierUsed(e){return this.getRepository().isFormElementIdentifierUsed(e)}createAndAddFormElement(e,t,i){const r=this.addFormElement(this.createFormElement(e,i),t,i);return r.set("renderables",r.get("renderables")),r}addFormElement(e,t,i){this.saveApplicationState(),this.getUtility().isUndefinedOrNull(t)&&(t=this.getCurrentlySelectedFormElement());const r=this.getRepository().findFormElement(t);return assert("object"===$.type(e),'Invalid parameter "formElement"',1475434337),this.getRepository().addFormElement(e,r,!0,i)}createFormElement(e,t){assert(this.getUtility().isNonEmptyString(e),'Invalid parameter "formElementType"',1475434336);const i=this.getRepository().getNextFreeFormElementIdentifier(e),r=this.getFormElementDefinitionByType(e,void 0);return this.getFactory().createFormElement({type:e,identifier:i,label:r.label||e},void 0,void 0,void 0,t)}removeFormElement(e,t){this.saveApplicationState();const i=this.getRepository().findFormElement(e),r=i.get("__parentRenderable");return this.getRepository().removeFormElement(i,!0,t),r}moveFormElement(e,t,i,r){this.saveApplicationState();let n=this.getRepository().findFormElement(e);const o=this.getRepository().findFormElement(i);return assert("after"===t||"before"===t||"inside"===t,'Invalid position "'+t+'"',1475378551),n=this.getRepository().moveFormElement(n,t,o,!0),(r=!!r)||n.get("__parentRenderable").set("renderables",n.get("__parentRenderable").get("renderables")),n}getPropertyCollectionElementConfiguration(e,t,i){let r,n;this.getUtility().isUndefinedOrNull(i)&&(i=this.getCurrentlySelectedFormElement());const o=this.getRepository().findFormElement(i);assert(this.getUtility().isNonEmptyString(e),'Invalid parameter "collectionElementIdentifier"',1475378555),assert(this.getUtility().isNonEmptyString(t),'Invalid parameter "collectionName"',1475378556);const a=this.getFormElementDefinitionByType(o.get("type"),void 0);return this.getUtility().isUndefinedOrNull(a.propertyCollections)?{}:(r=a.propertyCollections[t],assert(!this.getUtility().isUndefinedOrNull(r),'Invalid collection name "'+t+'"',1475446108),n=this.getRepository().findCollectionElementByIdentifierPath(e,r),$.extend(!0,{},n))}getIndexFromPropertyCollectionElement(e,t,i){this.getUtility().isUndefinedOrNull(i)&&(i=this.getCurrentlySelectedFormElement());const r=this.getRepository().findFormElement(i);assert(this.getUtility().isNonEmptyString(e),'Invalid parameter "collectionElementIdentifier"',1475378557),assert(this.getUtility().isNonEmptyString(t),'Invalid parameter "collectionName"',1475378558);return this.getRepository().getIndexFromPropertyCollectionElementByIdentifier(e,t,r)}createAndAddPropertyCollectionElement(e,t,i,r,n){return this.addPropertyCollectionElement(this.createPropertyCollectionElement(e,t,r),t,i,n)}addPropertyCollectionElement(e,t,i,r){let n;this.saveApplicationState(),this.getUtility().isUndefinedOrNull(i)&&(i=this.getCurrentlySelectedFormElement());const o=this.getRepository().findFormElement(i);return assert("object"===$.type(e),'Invalid parameter "collectionElement"',1475443301),assert(this.getUtility().isNonEmptyString(t),'Invalid parameter "collectionName"',1475443300),this.getUtility().isUndefinedOrNull(r)&&(n=o.get(t),"array"===$.type(n)&&n.length>0&&(r=n[n.length-1].identifier)),this.getRepository().addPropertyCollectionElement(e,t,o,r,!1)}createPropertyCollectionElement(e,t,i){return assert(this.getUtility().isNonEmptyString(e),'Invalid parameter "collectionElementIdentifier"',1475378559),assert(this.getUtility().isNonEmptyString(t),'Invalid parameter "collectionName"',1475378560),"object"!==$.type(i)&&(i={}),this.getFactory().createPropertyCollectionElement(e,i,t)}removePropertyCollectionElement(e,t,i,r){this.saveApplicationState(),this.getUtility().isUndefinedOrNull(i)&&(i=this.getCurrentlySelectedFormElement());const n=this.getRepository().findFormElement(i);assert(this.getUtility().isNonEmptyString(e),'Invalid parameter "collectionElementIdentifier"',1475378561),assert(this.getUtility().isNonEmptyString(t),'Invalid parameter "collectionName"',1475378562),this.getRepository().removePropertyCollectionElementByIdentifier(n,e,t,!0),(r=!!r)||this.getPublisherSubscriber().publish("core/formElement/somePropertyChanged",["__fakeProperty"])}movePropertyCollectionElement(e,t,i,r,n,o){this.saveApplicationState(),n=this.getRepository().findFormElement(n),assert("string"===$.type(e),'Invalid parameter "collectionElementToMove"',1477404352),assert("string"===$.type(i),'Invalid parameter "referenceCollectionElement"',1477404353),assert("after"===t||"before"===t,'Invalid position "'+t+'"',1477404354),assert(this.getUtility().isNonEmptyString(r),'Invalid parameter "collectionName"',1477404355),this.getRepository().movePropertyCollectionElement(e,t,i,r,n,o)}getFormElementDefinitionByType(e,t){assert(this.getUtility().isNonEmptyString(e),'Invalid parameter "elementType"',1475378563);const i=this.getRepository().getFormEditorDefinition("formElements",e);if(void 0!==t){const e=i[t];return null!==e&&"object"==typeof e?$.extend(!0,{},e):e}return null!==i&&"object"==typeof i?$.extend(!0,{},i):i}getFormElementDefinition(e,t){return e=this.getRepository().findFormElement(e),this.getFormElementDefinitionByType(e.get("type"),t)}getFormEditorDefinition(e,t){return this.getRepository().getFormEditorDefinition(e,t)}getFormElementPropertyValidatorDefinition(e){assert(this.getUtility().isNonEmptyString(e),'Invalid parameter "validatorIdentifier"',1475672362);const t=this.getRepository().getFormEditorDefinition("formElementPropertyValidators",e);return $.extend(!0,{},t)}getCurrentlySelectedPageIndex(){return this.getApplicationStateStack().getCurrentState("currentlySelectedPageIndex")}refreshCurrentlySelectedPageIndex(){this.getApplicationStateStack().setCurrentState("currentlySelectedPageIndex",this.getPageIndexFromFormElement(this.getCurrentlySelectedFormElement()))}getCurrentlySelectedPage(){const e=this.getRepository().getRootFormElement().get("renderables")[this.getCurrentlySelectedPageIndex()];return assert("object"===$.type(e),"No page found",1477786068),e}getLastTopLevelElementOnCurrentPage(){const e=this.getCurrentlySelectedPage().get("renderables");if(!this.getUtility().isUndefinedOrNull(e))return e[e.length-1]}getLastFormElementWithinParentFormElement(e){return(e=this.getRepository().findFormElement(e)).get("__identifierPath")===this.getRootFormElement().get("__identifierPath")?e:e.get("__parentRenderable").get("renderables")[e.get("__parentRenderable").get("renderables").length-1]}getPageIndexFromFormElement(e){return e=this.getRepository().findFormElement(e),this.getRepository().getIndexForEnclosingCompositeFormElementWhichIsOnTopLevelForFormElement(e)}renderCurrentFormPage(){this.renderFormPage(this.getCurrentlySelectedPageIndex())}renderFormPage(e){assert("number"===$.type(e),'Invalid parameter "pageIndex"',1475446442),this.getDataBackend().renderFormDefinitionPage(e)}findEnclosingCompositeFormElementWhichIsNotOnTopLevel(e){return this.getRepository().findEnclosingCompositeFormElementWhichIsNotOnTopLevel(this.getRepository().findFormElement(e))}findEnclosingGridRowFormElement(e){return this.getRepository().findEnclosingGridRowFormElement(this.getRepository().findFormElement(e))}getNonCompositeNonToplevelFormElements(){return this.getRepository().getNonCompositeNonToplevelFormElements()}isRootFormElementSelected(){return this.getCurrentlySelectedFormElement().get("__identifierPath")===this.getRootFormElement().get("__identifierPath")}getViewModel(){return this.viewModel}saveFormDefinition(){this.getDataBackend().saveFormDefinition()}run(){if(this.isRunning)throw"You can not run the app twice (1473200696)";try{this.bootstrap(),this.isRunning=!0}catch(e){Notification.error(TYPO3.lang["formEditor.error.headline"],TYPO3.lang["formEditor.error.message"]+"\r\n\r\n"+TYPO3.lang["formEditor.error.technicalReason"]+"\r\n"+e.message)}return this}saveApplicationState(){this.getApplicationStateStack().addAndReset({formDefinition:this.getApplicationStateStack().getCurrentState("formDefinition").clone(),currentlySelectedPageIndex:this.getApplicationStateStack().getCurrentState("currentlySelectedPageIndex"),currentlySelectedFormElementIdentifierPath:this.getApplicationStateStack().getCurrentState("currentlySelectedFormElementIdentifierPath")})}getDataBackend(){return Core.getDataBackend()}getFactory(){return Core.getFactory()}getRepository(){return Core.getRepository()}getPropertyValidationService(){return Core.getPropertyValidationService()}getApplicationStateStack(){return Core.getApplicationStateStack()}ajaxSetup(){$.ajaxSetup({beforeSend:()=>{this.getPublisherSubscriber().publish("ajax/beforeSend")},complete:()=>{this.getPublisherSubscriber().publish("ajax/complete")}})}dataBackendSetup(e,t,i){assert("object"===$.type(e),'Invalid parameter "endpoints"',1475379748),assert(this.getUtility().isNonEmptyString(t),'Invalid parameter "prototypeName"',1475927876),assert(this.getUtility().isNonEmptyString(i),'Invalid parameter "formPersistenceIdentifier"',1475379749),Core.getDataBackend().setEndpoints(e),Core.getDataBackend().setPrototypeName(t),Core.getDataBackend().setPersistenceIdentifier(i)}repositorySetup(e){assert("object"===$.type(e),'Invalid parameter "formEditorDefinitions"',1475379750),this.getRepository().setFormEditorDefinitions(e)}viewSetup(e){assert("function"===$.type(this.viewModel.bootstrap),'The view model does not implement the method "bootstrap"',1475492374),this.getUtility().isUndefinedOrNull(e)&&(e=[]),this.viewModel.bootstrap(formEditorInstance,e)}mediatorSetup(){assert("function"===$.type(this.mediator.bootstrap),'The mediator does not implement the method "bootstrap"',1475492032),this.mediator.bootstrap(formEditorInstance,this.viewModel)}applicationStateStackSetup(e,t){assert("object"===$.type(e),'Invalid parameter "rootFormElement"',1475379751),"number"!==$.type(t)&&(t=10),this.getApplicationStateStack().setMaximalStackSize(t),this.getApplicationStateStack().addAndReset({currentlySelectedPageIndex:0,currentlySelectedFormElementIdentifierPath:e.identifier},!0),this.getApplicationStateStack().setCurrentState("formDefinition",this.getFactory().createFormElement(e,void 0,void 0,!0))}bootstrap(){this.mediatorSetup(),this.ajaxSetup(),this.dataBackendSetup(this.configuration.endpoints,this.configuration.prototypeName,this.configuration.formPersistenceIdentifier),this.repositorySetup(this.configuration.formEditorDefinitions),this.applicationStateStackSetup(this.configuration.formDefinition,this.configuration.maximumUndoSteps),this.setCurrentlySelectedFormElement(this.getRepository().getRootFormElement()),this.viewSetup(this.configuration.additionalViewModelModules)}}let formEditorInstance=null;export function getInstance(e,t,i){return null===formEditorInstance&&(formEditorInstance=new FormEditor(e,t,i)),formEditorInstance} \ No newline at end of file -- GitLab