diff --git a/Build/Sources/TypeScript/form/backend/form-manager.ts b/Build/Sources/TypeScript/form/backend/form-manager.ts new file mode 100644 index 000000000000..5be379d7ecc5 --- /dev/null +++ b/Build/Sources/TypeScript/form/backend/form-manager.ts @@ -0,0 +1,178 @@ +/* + * 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-manager + */ + +// @todo once view-model.js is migrated: +// replace ViewModelLike with typeof import('@typo3/form/backend/form-manager/view-model') +interface ViewModelLike { + bootstrap: (formManager: FormManager) => void; +} + +export interface LabelValuePair { + label: string; + value: string; +} + +export type FormManagerConfiguration = { + selectablePrototypesConfiguration?: Array<{ + label: string; + identifier: string; + newFormTemplates: Array<{ + label: string; + templatePath: string; + }>; + }>, + accessibleFormStorageFolders?: LabelValuePair[], + endpoints?: { + [key: string]: string; + }, +}; + +export function assert(test: boolean|(() => boolean), message: string, messageCode: number): void { + if (typeof test === 'function') { + test = (test() !== false); + } + if (!test) { + message = message || 'Assertion failed'; + if (messageCode) { + message = message + ' (' + messageCode + ')'; + } + if ('undefined' !== typeof Error) { + throw new Error(message); + } + throw message; + } +} + +export class FormManager { + private isRunning: boolean = false; + private configuration: FormManagerConfiguration; + private viewModel: ViewModelLike; + + public constructor(configuration: FormManagerConfiguration, viewModel: ViewModelLike) { + this.configuration = configuration; + this.viewModel = viewModel; + } + + /** + * @todo deprecate, use exported `assert()` method instead + */ + public assert(test: boolean|(() => boolean), message: string, messageCode: number): void { + assert(test, message, messageCode); + } + + public getPrototypes(): LabelValuePair[] { + if (!Array.isArray(this.configuration.selectablePrototypesConfiguration)) { + return []; + } + + return this.configuration.selectablePrototypesConfiguration.map((selectablePrototype): LabelValuePair => { + return { + label: selectablePrototype.label, + value: selectablePrototype.identifier, + }; + }); + } + + public getTemplatesForPrototype(prototypeName: string): LabelValuePair[] { + assert('string' === typeof prototypeName, 'Invalid parameter "prototypeName"', 1475945286); + if (!Array.isArray(this.configuration.selectablePrototypesConfiguration)) { + return []; + } + + const templates: LabelValuePair[] = []; + this.configuration.selectablePrototypesConfiguration.forEach((selectablePrototype): void => { + if (!Array.isArray(selectablePrototype.newFormTemplates)) { + return; + } + + if (selectablePrototype.identifier !== prototypeName) { + return; + } + selectablePrototype.newFormTemplates.forEach((newFormTemplate): void => { + templates.push({ + label: newFormTemplate.label, + value: newFormTemplate.templatePath, + }); + }); + }); + + return templates; + } + + public getAccessibleFormStorageFolders(): LabelValuePair[] { + if (!Array.isArray(this.configuration.accessibleFormStorageFolders)) { + return []; + } + + return this.configuration.accessibleFormStorageFolders.map((folder): LabelValuePair => { + return { + label: folder.label, + value: folder.value, + }; + }); + } + + /** + * @throws 1477506508 + */ + public getAjaxEndpoint(endpointName: string): string { + assert(typeof this.configuration.endpoints[endpointName] !== 'undefined', 'Endpoint ' + endpointName + ' does not exist', 1477506508); + + return this.configuration.endpoints[endpointName]; + } + + /** + * @throws 1475942618 + */ + public run(): FormManager { + if (this.isRunning) { + throw 'You can not run the app twice (1475942618)'; + } + + this.bootstrap(); + this.isRunning = true; + return this; + } + + /** + * @throws 1475942906 + */ + private viewSetup(): void { + assert('function' === typeof this.viewModel.bootstrap, 'The view model does not implement the method "bootstrap"', 1475942906); + this.viewModel.bootstrap(this); + } + + /** + * @throws 1477506504 + */ + private bootstrap(): void { + this.configuration = this.configuration || {}; + assert('object' === typeof this.configuration.endpoints, 'Invalid parameter "endpoints"', 1477506504); + this.viewSetup(); + } +} + +let formManagerInstance: FormManager = null; +/** + * Return a singleton instance of a "FormManager" object. + */ +export function getInstance(configuration: FormManagerConfiguration, viewModel: ViewModelLike): FormManager { + if (formManagerInstance === null) { + formManagerInstance = new FormManager(configuration, viewModel); + } + return formManagerInstance; +} diff --git a/Build/Sources/TypeScript/form/backend/helper.ts b/Build/Sources/TypeScript/form/backend/helper.ts index 8e2397aea0fe..9d7d01a895c1 100644 --- a/Build/Sources/TypeScript/form/backend/helper.ts +++ b/Build/Sources/TypeScript/form/backend/helper.ts @@ -25,17 +25,12 @@ interface FormEditorLike { run(): FormEditorLike; } -interface FormManagerLike { - getInstance(options: any, viewModel: ViewModelLike): FormManagerLike; - run(): FormEditorLike; -} - // eslint-disable-next-line @typescript-eslint/no-empty-interface interface MediatorLike { } -// eslint-disable-next-line @typescript-eslint/no-empty-interface interface ViewModelLike { + bootstrap: (formManager: import('@typo3/form/backend/form-manager').FormManager) => void; } /** @@ -62,8 +57,11 @@ export class Helper { loadModule(requirements.app), loadModule(requirements.viewModel) ]).then((modules: [any, any]) => - ((app: FormManagerLike, viewModel: ViewModelLike) => { - window.TYPO3.FORMMANAGER_APP = app.getInstance(options, viewModel).run(); + (( + formManager: typeof import('@typo3/form/backend/form-manager'), + viewModel: ViewModelLike + ) => { + window.TYPO3.FORMMANAGER_APP = formManager.getInstance(options, viewModel).run(); })(...modules) ); }); diff --git a/Build/types/TYPO3/index.d.ts b/Build/types/TYPO3/index.d.ts index a90246857806..037badb0af5c 100644 --- a/Build/types/TYPO3/index.d.ts +++ b/Build/types/TYPO3/index.d.ts @@ -7,8 +7,8 @@ declare namespace TYPO3 { export let Backend: typeof import('@typo3/backend/viewport').default; export let ExtensionManager: typeof import('@typo3/extensionmanager/main').default; - export let FORMEDITOR_APP: any; // @todo migrate to typescript, then use: InstanceType; - export let FORMMANAGER_APP: any; // @todo migrate to typescript, then use: InstanceType; + export let FORMEDITOR_APP: any; // @todo migrate to typescript, then use: import('@typo3/form/backend/form-editor').FormEditor; + export let FORMMANAGER_APP: import('@typo3/form/backend/form-manager').FormManager; export let FormEngine: typeof import('@typo3/backend/form-engine').default; export let Icons: typeof import('@typo3/backend/icons').default; export let InfoWindow: typeof import('@typo3/backend/info-window').default; diff --git a/typo3/sysext/form/Resources/Public/JavaScript/backend/form-manager.js b/typo3/sysext/form/Resources/Public/JavaScript/backend/form-manager.js index 7c0545acc1e9..b36815126cf9 100644 --- a/typo3/sysext/form/Resources/Public/JavaScript/backend/form-manager.js +++ b/typo3/sysext/form/Resources/Public/JavaScript/backend/form-manager.js @@ -10,232 +10,4 @@ * * The TYPO3 project - inspiring people to share! */ - -/** - * Module: @typo3/form/backend/form-manager - */ -import $ from 'jquery'; - -const { - getInstance -} = factory($); - -export { - getInstance -}; - -function factory($) { - /** - * Return a static method named "getInstance". - * Use this method to create the formmanager app. - */ - return (function() { - - /** - * @private - * - * Hold the instance (Singleton Pattern) - */ - var _formManagerInstance = null; - - /** - * @public - * - * @param object _configuration - * @param object _viewModel - * @return object - */ - function FormManager(_configuration, _viewModel) { - - /** - * @private - * - * @var bool - */ - var _isRunning = false; - - /** - * @public - * - * @param mixed test - * @param string message - * @param int messageCode - * @return void - */ - function assert(test, message, messageCode) { - if ('function' === $.type(test)) { - test = (test() !== false); - } - if (!test) { - message = message || "Assertion failed"; - if (messageCode) { - message = message + ' (' + messageCode + ')'; - } - if ('undefined' !== typeof Error) { - throw new Error(message); - } - throw message; - } - }; - - /** - * @public - * - * @return object - */ - function getPrototypes() { - var prototypes = []; - - if ('array' === $.type(_configuration['selectablePrototypesConfiguration'])) { - for (var i = 0, len = _configuration['selectablePrototypesConfiguration'].length; i < len; ++i) { - prototypes.push({ - label: _configuration['selectablePrototypesConfiguration'][i]['label'], - value: _configuration['selectablePrototypesConfiguration'][i]['identifier'] - }); - } - } - return prototypes; - }; - - /** - * @public - * - * @param string prototypeName - * @return object - */ - function getTemplatesForPrototype(prototypeName) { - var templates = []; - assert('string' === $.type(prototypeName), 'Invalid parameter "prototypeName"', 1475945286); - if ('array' === $.type(_configuration['selectablePrototypesConfiguration'])) { - for (var i = 0, len1 = _configuration['selectablePrototypesConfiguration'].length; i < len1; ++i) { - if (_configuration['selectablePrototypesConfiguration'][i]['identifier'] !== prototypeName) { - continue; - } - if ('array' === $.type(_configuration['selectablePrototypesConfiguration'][i]['newFormTemplates'])) { - for (var j = 0, len2 = _configuration['selectablePrototypesConfiguration'][i]['newFormTemplates'].length; j < len2; ++j) { - templates.push({ - label: _configuration['selectablePrototypesConfiguration'][i]['newFormTemplates'][j]['label'], - value: _configuration['selectablePrototypesConfiguration'][i]['newFormTemplates'][j]['templatePath'] - }); - } - } - } - } - - return templates; - }; - - /** - * @public - * - * @param string prototypeName - * @return object - */ - function getAccessibleFormStorageFolders() { - var folders = []; - - if ('array' === $.type(_configuration['accessibleFormStorageFolders'])) { - for (var i = 0, len1 = _configuration['accessibleFormStorageFolders'].length; i < len1; ++i) { - folders.push({ - label: _configuration['accessibleFormStorageFolders'][i]['label'], - value: _configuration['accessibleFormStorageFolders'][i]['value'] - }); - } - } - return folders; - }; - - /** - * @public - * - * @param string prototypeName - * @return object - * @throws 1477506508 - */ - function getAjaxEndpoint(endpointName) { - var templates = []; - assert(typeof _configuration['endpoints'][endpointName] !== 'undefined', 'Endpoint ' + endpointName + ' does not exist', 1477506508); - - return _configuration['endpoints'][endpointName]; - }; - - /** - * @private - * - * @return void - * @throws 1475942906 - */ - function _viewSetup() { - assert('function' === $.type(_viewModel.bootstrap), 'The view model does not implement the method "bootstrap"', 1475942906); - _viewModel.bootstrap(_formManagerInstance); - }; - - /** - * @private - * - * @return void - * @throws 1477506504 - */ - function _bootstrap() { - _configuration = _configuration || {}; - assert('object' === $.type(_configuration['endpoints']), 'Invalid parameter "endpoints"', 1477506504); - _viewSetup(); - }; - - /** - * @public - * - * @return TYPO3/CMS/Form/Backend/FormManager - * @throws 1475942618 - */ - function run() { - if (_isRunning) { - throw 'You can not run the app twice (1475942618)'; - } - - _bootstrap(); - _isRunning = true; - return this; - }; - - /** - * Publish the public methods. - * Implements the "Revealing Module Pattern". - */ - return { - getPrototypes: getPrototypes, - getTemplatesForPrototype: getTemplatesForPrototype, - getAccessibleFormStorageFolders: getAccessibleFormStorageFolders, - getAjaxEndpoint: getAjaxEndpoint, - - assert: assert, - run: run - }; - }; - - /** - * Emulation of static methods - */ - return { - /** - * @public - * @static - * - * Implement the "Singleton Pattern". - * - * Return a singleton instance of a - * "FormManager" object. - * - * @param object configuration - * @param object viewModel - * @return object - */ - getInstance: function(configuration, viewModel) { - if (_formManagerInstance === null) { - _formManagerInstance = new FormManager(configuration, viewModel); - } - return _formManagerInstance; - } - }; - })(); -} +export function assert(t,e,o){if("function"==typeof t&&(t=!1!==t()),!t){if(e=e||"Assertion failed",o&&(e=e+" ("+o+")"),"undefined"!=typeof Error)throw new Error(e);throw e}}export class FormManager{constructor(t,e){this.isRunning=!1,this.configuration=t,this.viewModel=e}assert(t,e,o){assert(t,e,o)}getPrototypes(){return Array.isArray(this.configuration.selectablePrototypesConfiguration)?this.configuration.selectablePrototypesConfiguration.map((t=>({label:t.label,value:t.identifier}))):[]}getTemplatesForPrototype(t){if(assert("string"==typeof t,'Invalid parameter "prototypeName"',1475945286),!Array.isArray(this.configuration.selectablePrototypesConfiguration))return[];const e=[];return this.configuration.selectablePrototypesConfiguration.forEach((o=>{Array.isArray(o.newFormTemplates)&&o.identifier===t&&o.newFormTemplates.forEach((t=>{e.push({label:t.label,value:t.templatePath})}))})),e}getAccessibleFormStorageFolders(){return Array.isArray(this.configuration.accessibleFormStorageFolders)?this.configuration.accessibleFormStorageFolders.map((t=>({label:t.label,value:t.value}))):[]}getAjaxEndpoint(t){return assert(void 0!==this.configuration.endpoints[t],"Endpoint "+t+" does not exist",1477506508),this.configuration.endpoints[t]}run(){if(this.isRunning)throw"You can not run the app twice (1475942618)";return this.bootstrap(),this.isRunning=!0,this}viewSetup(){assert("function"==typeof this.viewModel.bootstrap,'The view model does not implement the method "bootstrap"',1475942906),this.viewModel.bootstrap(this)}bootstrap(){this.configuration=this.configuration||{},assert("object"==typeof this.configuration.endpoints,'Invalid parameter "endpoints"',1477506504),this.viewSetup()}}let formManagerInstance=null;export function getInstance(t,e){return null===formManagerInstance&&(formManagerInstance=new FormManager(t,e)),formManagerInstance} \ No newline at end of file