diff --git a/Build/Sources/TypeScript/form/backend/form-editor/stage-component.ts b/Build/Sources/TypeScript/form/backend/form-editor/stage-component.ts new file mode 100644 index 0000000000000000000000000000000000000000..0bc83bcc3e7a09410ed2c1b9bdc43c5fe13e781b --- /dev/null +++ b/Build/Sources/TypeScript/form/backend/form-editor/stage-component.ts @@ -0,0 +1,901 @@ +/* + * 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/stage-component + */ +import $ from 'jquery'; +import * as Helper from '@typo3/form/backend/form-editor/helper'; +import Icons from '@typo3/backend/icons'; +import Sortable from 'sortablejs'; + +import type { + FormEditor, + ViewModel, +} from '@typo3/form/backend/form-editor'; +import type { + Utility, + FormElement, + FormElementDefinition, + PublisherSubscriber, +} from '@typo3/form/backend/form-editor/core'; +import type { + Configuration as HelperConfiguration, +} from '@typo3/form/backend/form-editor/helper'; +import type { + InsertElementsModalConfiguration +} from '@typo3/form/backend/form-editor/modals-component'; + +interface Configuration extends Partial<HelperConfiguration> { + isSortable: boolean, +} + +const defaultConfiguration: Configuration = { + domElementClassNames: { + formElementIsComposit: 't3-form-element-composit', + formElementIsTopLevel: 't3-form-element-toplevel', + noNesting: 'mjs-nestedSortable-no-nesting', + selected: 'selected', + sortable: 'sortable', + previewViewPreviewElement: 't3-form-element-preview' + }, + domElementDataAttributeNames: { + abstractType: 'data-element-abstract-type', + noSorting: 'data-no-sorting' + }, + domElementDataAttributeValues: { + abstractViewToolbar: 'elementToolbar', + abstractViewToolbarNewElement: 'stageElementToolbarNewElement', + abstractViewToolbarNewElementSplitButton: 'stageElementToolbarNewElementSplitButton', + abstractViewToolbarNewElementSplitButtonAfter: 'stageElementToolbarNewElementSplitButtonAfter', + abstractViewToolbarNewElementSplitButtonInside: 'stageElementToolbarNewElementSplitButtonInside', + abstractViewToolbarRemoveElement: 'stageElementToolbarRemoveElement', + buttonHeaderRedo: 'redoButton', + buttonHeaderUndo: 'undoButton', + buttonPaginationPrevious: 'buttonPaginationPrevious', + buttonPaginationNext: 'buttonPaginationNext', + 'FormElement-_ElementToolbar': 'FormElement-_ElementToolbar', + 'FormElement-_UnknownElement': 'FormElement-_UnknownElement', + 'FormElement-AdvancedPassword': 'FormElement-AdvancedPassword', + 'FormElement-Checkbox': 'FormElement-Checkbox', + 'FormElement-ContentElement': 'FormElement-ContentElement', + 'FormElement-CountrySelect': 'FormElement-CountrySelect', + 'FormElement-DatePicker': 'FormElement-DatePicker', + 'FormElement-Fieldset': 'FormElement-Fieldset', + 'FormElement-GridRow': 'FormElement-GridRow', + 'FormElement-FileUpload': 'FormElement-FileUpload', + 'FormElement-Hidden': 'FormElement-Hidden', + 'FormElement-ImageUpload': 'FormElement-ImageUpload', + 'FormElement-MultiCheckbox': 'FormElement-MultiCheckbox', + 'FormElement-MultiSelect': 'FormElement-MultiSelect', + 'FormElement-Page': 'FormElement-Page', + 'FormElement-Password': 'FormElement-Password', + 'FormElement-RadioButton': 'FormElement-RadioButton', + 'FormElement-SingleSelect': 'FormElement-SingleSelect', + 'FormElement-StaticText': 'FormElement-StaticText', + 'FormElement-SummaryPage': 'FormElement-SummaryPage', + 'FormElement-Text': 'FormElement-Text', + 'FormElement-Textarea': 'FormElement-Textarea', + 'FormElement-Email': 'FormElement-Email', + 'FormElement-Url': 'FormElement-Url', + 'FormElement-Telephone': 'FormElement-Telephone', + 'FormElement-Number': 'FormElement-Number', + 'FormElement-Date': 'FormElement-Date', + formElementIcon: 'elementIcon', + iconValidator: 'form-validator', + multiValueContainer: 'multiValueContainer', + paginationTitle: 'paginationTitle', + stageHeadline: 'formDefinitionLabel', + stagePanel: 'stagePanel', + validatorsContainer: 'validatorsContainer', + validatorIcon: 'validatorIcon' + }, + isSortable: true +}; + +let configuration: Configuration = null; + +let formEditorApp: FormEditor = null; + +let stageDomElement: JQuery = null; + +function getFormEditorApp(): FormEditor { + return formEditorApp; +} + +function getHelper(_configuration?: HelperConfiguration): typeof Helper { + if (getUtility().isUndefinedOrNull(_configuration)) { + return Helper.setConfiguration(configuration); + } + return Helper.setConfiguration(_configuration); +} + +function getUtility(): Utility { + return getFormEditorApp().getUtility(); +} + +function getViewModel(): ViewModel { + return getFormEditorApp().getViewModel(); +} + +function assert(test: boolean|(() => boolean), message: string, messageCode: number): void { + return getFormEditorApp().assert(test, message, messageCode); +} + +function getRootFormElement(): FormElement { + return getFormEditorApp().getRootFormElement(); +} + +function getCurrentlySelectedFormElement(): FormElement { + return getFormEditorApp().getCurrentlySelectedFormElement(); +} + +function getPublisherSubscriber(): PublisherSubscriber { + return getFormEditorApp().getPublisherSubscriber(); +} + +function getFormElementDefinition<T extends keyof FormElementDefinition>( + formElement: FormElement, + formElementDefinitionKey?: T +): T extends keyof FormElementDefinition ? FormElementDefinition[T] : FormElementDefinition { + return getFormEditorApp().getFormElementDefinition(formElement, formElementDefinitionKey); +} + +function setTemplateTextContent(domElement: HTMLElement, content: string): void { + if (getUtility().isNonEmptyString(content)) { + $(domElement).text(content); + } +} + +/** + * @publish view/stage/abstract/render/template/perform + */ +function renderTemplateDispatcher(formElement: FormElement, template: JQuery): void { + switch (formElement.get('type')) { + case 'Checkbox': + renderCheckboxTemplate(formElement, template); + break; + case 'FileUpload': + case 'ImageUpload': + renderFileUploadTemplates(formElement, template); + break; + case 'CountrySelect': + case 'SingleSelect': + case 'RadioButton': + case 'MultiSelect': + case 'MultiCheckbox': + renderSelectTemplates(formElement, template); + break; + case 'Textarea': + case 'AdvancedPassword': + case 'Password': + case 'Text': + case 'Email': + case 'Url': + case 'Telephone': + case 'Number': + case 'DatePicker': + case 'Date': + renderSimpleTemplateWithValidators(formElement, template); + break; + case 'Fieldset': + case 'GridRow': + case 'SummaryPage': + case 'Page': + case 'StaticText': + case 'Hidden': + case 'ContentElement': + renderSimpleTemplate(formElement, template); + break; + default: + break; + } + getPublisherSubscriber().publish('view/stage/abstract/render/template/perform', [formElement, template]); +} + +/** + * @throws 1478987818 + */ +function renderNestedSortableListItem(formElement: FormElement): JQuery { + let childList, template; + + const listItem = $('<li></li>'); + if (!getFormElementDefinition(formElement, '_isCompositeFormElement')) { + listItem.addClass(getHelper().getDomElementClassName('noNesting')); + } + + if (getFormElementDefinition(formElement, '_isTopLevelFormElement')) { + listItem.addClass(getHelper().getDomElementClassName('formElementIsTopLevel')); + } + if (getFormElementDefinition(formElement, '_isCompositeFormElement')) { + listItem.addClass(getHelper().getDomElementClassName('formElementIsComposit')); + } + + try { + template = getHelper().getTemplate('FormElement-' + formElement.get('type')).clone(); + } catch (error) { + template = getHelper().getTemplate('FormElement-_UnknownElement').clone(); + assert( + template.length > 0, + 'No template found for element "' + formElement.get('__identifierPath') + '"', + 1478987818 + ); + } + + template = $('<div></div>') + .attr(getHelper().getDomElementDataAttribute('elementIdentifier'), formElement.get('__identifierPath')) + .append($(template.html())); + + if (getFormElementDefinition(formElement, '_isCompositeFormElement')) { + template.attr(getHelper().getDomElementDataAttribute('abstractType'), 'isCompositeFormElement'); + } + if (getFormElementDefinition(formElement, '_isTopLevelFormElement')) { + template.attr(getHelper().getDomElementDataAttribute('abstractType'), 'isTopLevelFormElement'); + } + listItem.append(template); + + renderTemplateDispatcher(formElement, template); + + const childFormElements = formElement.get('renderables'); + childList = null; + if ('array' === $.type(childFormElements)) { + childList = $('<ol></ol>'); + childList.addClass(getHelper().getDomElementClassName('sortable')); + for (let i = 0, len = childFormElements.length; i < len; ++i) { + childList.append(renderNestedSortableListItem(childFormElements[i])); + } + } + + if (childList) { + listItem.append(childList); + } + return listItem; +} + +/** + * @publish view/stage/abstract/dnd/start + * @publish view/stage/abstract/dnd/stop + * @publish view/stage/abstract/dnd/change + * @publish view/stage/abstract/dnd/update + */ +function addSortableEvents(): void { + const sortableLists = stageDomElement.get(0).querySelectorAll('ol.' + getHelper().getDomElementClassName('sortable')); + const draggableSelector = 'li:not(' + getHelper().getDomElementDataAttribute('noSorting', 'bracesWithKey') + ')'; + const handleSelector = 'div' + getHelper().getDomElementDataAttribute('elementIdentifier', 'bracesWithKey'); + + sortableLists.forEach(function (sortableList: HTMLElement) { + sortableList.querySelectorAll(handleSelector).forEach(function (draggable) { + draggable.classList.add('form-sortable-handle'); + }); + + new Sortable(sortableList, { + group: 'stage-nodes', + handle: handleSelector, + draggable: draggableSelector, + animation: 200, + swapThreshold: 0.6, + dragClass: 'form-sortable-drag', + ghostClass: 'form-sortable-ghost', + onStart: function (e) { + getPublisherSubscriber().publish('view/stage/abstract/dnd/start', [$(e.item), $(e.item)]); + }, + onChange: function (e) { + let enclosingCompositeFormElement; + const parentFormElementIdentifierPath = getAbstractViewParentFormElementIdentifierPathWithinDomElement($(e.item)); + + if (parentFormElementIdentifierPath) { + enclosingCompositeFormElement = getFormEditorApp() + .findEnclosingCompositeFormElementWhichIsNotOnTopLevel(parentFormElementIdentifierPath); + } + getPublisherSubscriber().publish('view/stage/abstract/dnd/change', [ + $(e.item), + parentFormElementIdentifierPath, enclosingCompositeFormElement + ]); + }, + onEnd: function (e) { + const movedFormElementIdentifierPath = getAbstractViewFormElementIdentifierPathWithinDomElement($(e.item)); + const previousFormElementIdentifierPath = getAbstractViewSiblingFormElementIdentifierPathWithinDomElement($(e.item), 'prev'); + const nextFormElementIdentifierPath = getAbstractViewSiblingFormElementIdentifierPathWithinDomElement($(e.item), 'next'); + + getPublisherSubscriber().publish('view/stage/abstract/dnd/update', [ + $(e.item), + movedFormElementIdentifierPath, + previousFormElementIdentifierPath, + nextFormElementIdentifierPath + ]); + getPublisherSubscriber().publish('view/stage/abstract/dnd/stop', [ + getAbstractViewFormElementIdentifierPathWithinDomElement($(e.item)) + ]); + }, + }); + }); +} + +export function getStageDomElement(): JQuery { + return stageDomElement; +} + +/** + * @throws 1479037151 + */ +export function buildTitleByFormElement(formElement?: FormElement): HTMLElement { + if (getUtility().isUndefinedOrNull(formElement)) { + formElement = getRootFormElement(); + } + assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1479037151); + + const span = document.createElement('span'); + span.textContent = formElement.get('label') ? formElement.get('label') : formElement.get('identifier'); + return span; +} + +export function setStageHeadline(title: string): void { + if (getUtility().isUndefinedOrNull(title)) { + title = buildTitleByFormElement().textContent; + } + + $(getHelper().getDomElementDataIdentifierSelector('stageHeadline')).text(title); +} + +export function getStagePanelDomElement(): JQuery { + return $(getHelper().getDomElementDataIdentifierSelector('stagePanel')); +} + +export function renderPagination(): void { + const pageCount = getRootFormElement().get('renderables').length; + + getViewModel().enableButton($(getHelper().getDomElementDataIdentifierSelector('buttonPaginationPrevious'))); + getViewModel().enableButton($(getHelper().getDomElementDataIdentifierSelector('buttonPaginationNext'))); + + if (getFormEditorApp().getCurrentlySelectedPageIndex() === 0) { + getViewModel().disableButton($(getHelper().getDomElementDataIdentifierSelector('buttonPaginationPrevious'))); + } + + if (pageCount === 1 || getFormEditorApp().getCurrentlySelectedPageIndex() === (pageCount - 1)) { + getViewModel().disableButton($(getHelper().getDomElementDataIdentifierSelector('buttonPaginationNext'))); + } + + const currentPage = getFormEditorApp().getCurrentlySelectedPageIndex() + 1; + $(getHelper().getDomElementDataIdentifierSelector('paginationTitle')).text( + getFormElementDefinition(getRootFormElement(), 'paginationTitle') + .replace('{0}', currentPage.toString()) + .replace('{1}', pageCount) + ); +} + +export function renderUndoRedo(): void { + getViewModel().enableButton($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderUndo'))); + getViewModel().enableButton($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderRedo'))); + + if (getFormEditorApp().getCurrentApplicationStatePosition() + 1 >= getFormEditorApp().getCurrentApplicationStates()) { + getViewModel().disableButton($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderUndo'))); + } + if (getFormEditorApp().getCurrentApplicationStatePosition() === 0) { + getViewModel().disableButton($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderRedo'))); + } +} + +export function getAllFormElementDomElements(): JQuery { + return $(getHelper().getDomElementDataAttribute('elementIdentifier', 'bracesWithKey'), + stageDomElement + ); +} + +/* ************************************************************* + * Abstract stage + * ************************************************************/ + +/** + * @throws 1478721208 + */ +export function renderFormDefinitionPageAsSortableList(pageIndex: number): JQuery { + assert( + 'number' === $.type(pageIndex), + 'Invalid parameter "pageIndex"', + 1478721208 + ); + + return $('<ol></ol>') + .append(renderNestedSortableListItem(getRootFormElement().get('renderables')[pageIndex])); +} + +export function getAbstractViewParentFormElementWithinDomElement(element: HTMLElement | JQuery): JQuery { + return $(element) + .parent() + .closest('li') + .find(getHelper().getDomElementDataAttribute('elementIdentifier', 'bracesWithKey')) + .first(); +} + +export function getAbstractViewParentFormElementIdentifierPathWithinDomElement(element: HTMLElement | JQuery): string { + return getAbstractViewParentFormElementWithinDomElement(element) + .attr(getHelper().getDomElementDataAttribute('elementIdentifier')); +} + +export function getAbstractViewFormElementWithinDomElement(element: HTMLElement | JQuery): JQuery { + return $(element) + .find(getHelper().getDomElementDataAttribute('elementIdentifier', 'bracesWithKey')) + .first(); +} + +export function getAbstractViewFormElementIdentifierPathWithinDomElement(element: HTMLElement | JQuery): string { + return getAbstractViewFormElementWithinDomElement($(element)) + .attr(getHelper().getDomElementDataAttribute('elementIdentifier')); +} + +export function getAbstractViewSiblingFormElementIdentifierPathWithinDomElement(element: HTMLElement | JQuery, position: string): string { + if (getUtility().isUndefinedOrNull(position)) { + position = 'prev'; + } + const formElementIdentifierPath = getAbstractViewFormElementIdentifierPathWithinDomElement(element); + element = (position === 'prev') ? $(element).prev('li') : $(element).next('li'); + return element.find(getHelper().getDomElementDataAttribute('elementIdentifier', 'bracesWithKey')) + .not(getHelper().getDomElementDataAttribute('elementIdentifier', 'bracesWithKeyValue', [formElementIdentifierPath])) + .first() + .attr(getHelper().getDomElementDataAttribute('elementIdentifier')); +} + +export function getAbstractViewFormElementDomElement(formElement?: FormElement | string): JQuery { + let formElementIdentifierPath; + + if (typeof formElement === 'string') { + formElementIdentifierPath = formElement; + } else { + if (getUtility().isUndefinedOrNull(formElement)) { + formElementIdentifierPath = getCurrentlySelectedFormElement().get('__identifierPath'); + } else { + formElementIdentifierPath = formElement.get('__identifierPath'); + } + } + return $(getHelper() + .getDomElementDataAttribute('elementIdentifier', 'bracesWithKeyValue', [formElementIdentifierPath]), stageDomElement); +} + +export function removeAllStageToolbars(): void { + $(getHelper().getDomElementDataIdentifierSelector('abstractViewToolbar'), stageDomElement).off().empty().remove(); +} + +/** + * @publish view/insertElements/perform/after + * @publish view/insertElements/perform/inside + * @throws 1479035778 + */ +export function createAbstractViewFormElementToolbar(formElement: FormElement): JQuery { + let template: JQuery; + assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1479035778); + + const formElementTypeDefinition = getFormElementDefinition(formElement, undefined); + if (formElementTypeDefinition._isTopLevelFormElement) { + return $(); + } + + template = getHelper().getTemplate('FormElement-_ElementToolbar').clone(); + if (!template.length) { + return $(); + } + + template = $($(template.html())); + + getHelper().getTemplatePropertyDomElement('_type', template).text(getFormElementDefinition(formElement, 'label')); + getHelper().getTemplatePropertyDomElement('_identifier', template).text(formElement.get('identifier')); + + if (formElementTypeDefinition._isCompositeFormElement) { + getViewModel().hideComponent($(getHelper().getDomElementDataIdentifierSelector('abstractViewToolbarNewElement'), template)); + + $(getHelper().getDomElementDataIdentifierSelector('abstractViewToolbarNewElementSplitButtonAfter'), template).on('click', function() { + getPublisherSubscriber().publish('view/stage/abstract/elementToolbar/button/newElement/clicked', [ + 'view/insertElements/perform/after', + { + disableElementTypes: [], + onlyEnableElementTypes: [] + } + ] + ); + }); + + $(getHelper().getDomElementDataIdentifierSelector('abstractViewToolbarNewElementSplitButtonInside'), template).on('click', function() { + getPublisherSubscriber().publish('view/stage/abstract/elementToolbar/button/newElement/clicked', [ + 'view/insertElements/perform/inside', + { + disableElementTypes: [], + onlyEnableElementTypes: [] + } + ] + ); + }); + } else { + getViewModel().hideComponent($(getHelper().getDomElementDataIdentifierSelector('abstractViewToolbarNewElementSplitButton'), template)); + + $(getHelper().getDomElementDataIdentifierSelector('abstractViewToolbarNewElement'), template).on('click', function() { + getPublisherSubscriber().publish( + 'view/stage/abstract/elementToolbar/button/newElement/clicked', [ + 'view/insertElements/perform/after', + { + disableElementTypes: [] + } + ] + ); + }); + } + + $(getHelper().getDomElementDataIdentifierSelector('abstractViewToolbarRemoveElement'), template).on('click', function() { + getViewModel().showRemoveFormElementModal(); + }); + + return template; +} + +export function createAndAddAbstractViewFormElementToolbar( + selectedFormElementDomElement: JQuery, + formElement: FormElement, + useFadeEffect: boolean +): void { + if (getUtility().isUndefinedOrNull(formElement)) { + formElement = getCurrentlySelectedFormElement(); + } + + if (useFadeEffect) { + createAbstractViewFormElementToolbar(formElement).fadeOut(0, function(this: HTMLElement) { + selectedFormElementDomElement.prepend($(this)); + $(getHelper().getDomElementDataIdentifierSelector('abstractViewToolbar'), selectedFormElementDomElement).fadeIn('fast'); + }); + } else { + selectedFormElementDomElement.prepend(createAbstractViewFormElementToolbar(formElement)); + } +} + +/** + * @publish view/stage/dnd/stop + * @publish view/stage/element/clicked + * @throws 1478169511 + */ +export function renderAbstractStageArea(pageIndex: number, callback: () => void) { + if (getUtility().isUndefinedOrNull(pageIndex)) { + pageIndex = getFormEditorApp().getCurrentlySelectedPageIndex(); + } + stageDomElement.off().empty().append(renderFormDefinitionPageAsSortableList(pageIndex)); + + stageDomElement.on('click', function(e) { + const formElementIdentifierPath = $(e.target) + .closest(getHelper().getDomElementDataAttribute('elementIdentifier', 'bracesWithKey')) + .attr(getHelper().getDomElementDataAttribute('elementIdentifier')); + if ( + getUtility().isUndefinedOrNull(formElementIdentifierPath) + || !getUtility().isNonEmptyString(formElementIdentifierPath) + ) { + return; + } + + getPublisherSubscriber().publish('view/stage/element/clicked', [formElementIdentifierPath]); + }); + + if (configuration.isSortable) { + addSortableEvents(); + } + + if ('function' === $.type(callback)) { + callback(); + } +} + + +/* ************************************************************* + * Preview stage + * ************************************************************/ + +/** + * @throws 1475424409 + */ +export function renderPreviewStageArea(html: string): void { + assert(getUtility().isNonEmptyString(html), 'Invalid parameter "html"', 1475424409); + + stageDomElement.off().empty().html(html); + + $(':input', stageDomElement).prop('disabled', 'disabled').on('click dblclick select focus keydown keypress keyup mousedown mouseup', function(e) { + return e.preventDefault(); + }); + + $('form', stageDomElement).submit(function(e) { + return e.preventDefault(); + }); + + getAllFormElementDomElements().each(function(this: HTMLElement) { + const formElement = getFormEditorApp() + .getFormElementByIdentifierPath($(this).data('elementIdentifierPath')); + + if ( + !getFormElementDefinition(formElement, '_isTopLevelFormElement') + ) { + $(this).attr('title', 'identifier: ' + formElement.get('identifier') + ' (type: ' + formElement.get('type') + ')'); + } + + if (getFormElementDefinition(formElement, '_isTopLevelFormElement')) { + $(this).addClass(getHelper().getDomElementClassName('formElementIsTopLevel')); + } + if (getFormElementDefinition(formElement, '_isCompositeFormElement')) { + $(this).addClass(getHelper().getDomElementClassName('formElementIsComposit')); + } + }); + +} + +/* ************************************************************* + * Template rendering + * ************************************************************/ + +export function eachTemplateProperty( + formElement: FormElement, + template: JQuery, + callback?: (propertyPath: string, propertyValue: unknown, element: HTMLElement) => void +) { + $(getHelper().getDomElementDataAttribute('templateProperty', 'bracesWithKey'), template).each(function(i, element) { + const propertyPath = $(element).attr(getHelper().getDomElementDataAttribute('templateProperty')); + const propertyValue = formElement.get(propertyPath); + + if ('function' === $.type(callback)) { + callback(propertyPath, propertyValue, element as HTMLElement); + } + }); +} + +export function renderCheckboxTemplate(formElement: FormElement, template: JQuery) { + renderSimpleTemplateWithValidators(formElement, template); + + eachTemplateProperty(formElement, template, function(propertyPath, propertyValue, domElement) { + if ( + ('boolean' === $.type(propertyValue) && propertyValue) + || propertyValue === 'true' + || propertyValue === 1 + || propertyValue === '1' + ) { + $(domElement).addClass(getHelper().getDomElementClassName('noNesting')); + } + }); +} + +/** + * @throws 1479035696 + */ +export function renderSimpleTemplate(formElement: FormElement, template: JQuery): void { + assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1479035696); + + eachTemplateProperty(formElement, template, (propertyPath, propertyValue: string, domElement) => { + setTemplateTextContent(domElement, propertyValue); + }); + + Icons.getIcon( + getFormElementDefinition(formElement, 'iconIdentifier'), + Icons.sizes.small, + null, + Icons.states.default, + Icons.markupIdentifiers.inline + ).then(function(icon) { + $(getHelper().getDomElementDataIdentifierSelector('formElementIcon'), template) + .append($(icon).addClass(getHelper().getDomElementClassName('icon'))); + }); + + getHelper() + .getTemplatePropertyDomElement('_type', template) + .append(document.createTextNode(getFormElementDefinition(formElement, 'label'))); + getHelper() + .getTemplatePropertyDomElement('_identifier', template) + .append(document.createTextNode(formElement.get('identifier'))); +} + +/** + * @throws 1479035674 + */ +export function renderSimpleTemplateWithValidators(formElement: FormElement, template: JQuery): void { + assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1479035674); + + renderSimpleTemplate(formElement, template); + + const validatorsTemplateContent = $( + getHelper().getDomElementDataIdentifierSelector('validatorsContainer'), + $(template) + ).clone(); + + $(getHelper().getDomElementDataIdentifierSelector('validatorsContainer'), $(template)).empty(); + const validators = formElement.get('validators'); + + if ('array' === $.type(validators)) { + let validatorsCountWithoutRequired = 0; + if (validators.length > 0) { + for (let i = 0, len = validators.length; i < len; ++i) { + if ('NotEmpty' === validators[i].identifier) { + getHelper() + .getTemplatePropertyDomElement('_required', template) + .text('*'); + continue; + } + validatorsCountWithoutRequired++; + + const collectionElementConfiguration = getFormEditorApp() + .getFormEditorDefinition('validators', validators[i].identifier); + const rowTemplate = $($(validatorsTemplateContent).clone()); + + getHelper() + .getTemplatePropertyDomElement('_label', rowTemplate) + .append(document.createTextNode(collectionElementConfiguration.label)); + $(getHelper().getDomElementDataIdentifierSelector('validatorsContainer'), $(template)) + .append(rowTemplate.html()); + } + + if (validatorsCountWithoutRequired > 0) { + Icons.getIcon( + getHelper().getDomElementDataAttributeValue('iconValidator'), + Icons.sizes.small, + null, + Icons.states.default, + Icons.markupIdentifiers.inline + ).then(function(icon) { + $(getHelper().getDomElementDataIdentifierSelector('validatorIcon'), $(template)) + .append($(icon).addClass(getHelper().getDomElementClassName('icon'))); + }); + } + } + } +} + +export function renderSelectTemplates(formElement: FormElement, template: JQuery): void { + const multiValueTemplateContent = $( + getHelper().getDomElementDataIdentifierSelector('multiValueContainer'), + $(template) + ).clone(); + $(getHelper().getDomElementDataIdentifierSelector('multiValueContainer'), $(template)).empty(); + + renderSimpleTemplateWithValidators(formElement, template); + + const propertyPath = $(getHelper().getDomElementDataIdentifierSelector('multiValueContainer'), $(template)) + .attr(getHelper().getDomElementDataAttribute('templateProperty')); + + const propertyValue = formElement.get(propertyPath); + + const appendMultiValue = (label: string, value: string, defaultValue: Record<string, string>) => { + let isPreselected = false; + const rowTemplate = $($(multiValueTemplateContent).clone()); + + for (const defaultValueKey of Object.keys(defaultValue)) { + if (defaultValue[defaultValueKey] === value) { + isPreselected = true; + break; + } + } + + getHelper().getTemplatePropertyDomElement('_label', rowTemplate).append(document.createTextNode(label)); + + if (isPreselected) { + getHelper().getTemplatePropertyDomElement('_label', rowTemplate).addClass( + getHelper().getDomElementClassName('selected') + ); + } + + $(getHelper().getDomElementDataIdentifierSelector('multiValueContainer'), $(template)) + .append(rowTemplate.html()); + }; + + let defaultValue = formElement.get('defaultValue'); + + if (getFormEditorApp().getUtility().isUndefinedOrNull(defaultValue)) { + defaultValue = {}; + } else if ('string' === $.type(defaultValue)) { + defaultValue = { 0: defaultValue }; + } + + if ('object' === $.type(propertyValue)) { + for (const propertyValueKey of Object.keys(propertyValue)) { + appendMultiValue(propertyValue[propertyValueKey], propertyValueKey, defaultValue); + } + } else if ('array' === $.type(propertyValue)) { + for (const propertyValueKey of Object.keys(propertyValue)) { + if (getUtility().isUndefinedOrNull(propertyValue[propertyValueKey]._label)) { + appendMultiValue(propertyValue[propertyValueKey], propertyValueKey, defaultValue); + } else { + appendMultiValue(propertyValue[propertyValueKey]._label, propertyValue[propertyValueKey]._value, defaultValue); + } + } + } +} + +export function renderFileUploadTemplates(formElement: FormElement, template: JQuery): void { + const multiValueTemplateContent = $( + getHelper().getDomElementDataIdentifierSelector('multiValueContainer'), + $(template) + ).clone(); + $(getHelper().getDomElementDataIdentifierSelector('multiValueContainer'), $(template)).empty(); + + renderSimpleTemplateWithValidators(formElement, template); + + const propertyPath = $(getHelper().getDomElementDataIdentifierSelector('multiValueContainer'), $(template)) + .attr(getHelper().getDomElementDataAttribute('templateProperty')); + const propertyValue = formElement.get(propertyPath); + + const appendMultiValue = function(value: string) { + const rowTemplate = $($(multiValueTemplateContent).clone()); + + getHelper().getTemplatePropertyDomElement('_value', rowTemplate).append(value); + $(getHelper().getDomElementDataIdentifierSelector('multiValueContainer'), $(template)) + .append(rowTemplate.html()); + }; + + if ('object' === $.type(propertyValue)) { + for (const propertyValueKey of Object.keys(propertyValue)) { + appendMultiValue(propertyValue[propertyValueKey]); + } + } else if ('array' === $.type(propertyValue)) { + for (let i = 0, len = propertyValue.length; i < len; ++i) { + appendMultiValue(propertyValue[i]); + } + } +} + +/** + * @throws 1478992119 + */ +export function bootstrap( + this: typeof import('./stage-component'), + _formEditorApp: FormEditor, + appendToDomElement: JQuery, + customConfiguration?: Configuration +): typeof import('./stage-component') { + formEditorApp = _formEditorApp; + assert('object' === $.type(appendToDomElement), 'Invalid parameter "appendToDomElement"', 1478992119); + stageDomElement = $(appendToDomElement); + configuration = $.extend(true, defaultConfiguration, customConfiguration || {}); + Helper.bootstrap(formEditorApp); + return this; +} + +declare global { + interface PublisherSubscriberTopicArgumentsMap { + 'view/stage/abstract/render/template/perform': readonly [ + formElement: FormElement, + template: JQuery + ]; + 'view/stage/abstract/dnd/start': readonly [ + draggedFormElementDomElement: HTMLElement | JQuery, + draggedFormPlaceholderDomElement: HTMLElement | JQuery, + ]; + 'view/stage/abstract/dnd/change': readonly [ + placeholderDomElement: JQuery, + parentFormElementIdentifierPath: string, + enclosingCompositeFormElement: FormElement + ]; + 'view/stage/abstract/dnd/update': readonly [ + movedDomElement: JQuery, + movedFormElementIdentifierPath: string, + previousFormElementIdentifierPath: string, + nextFormElementIdentifierPath: string, + ]; + 'view/stage/abstract/dnd/stop': readonly [ + draggedFormElementIdentifierPath: string + ]; + 'view/stage/element/clicked': readonly [ + formElementIdentifierPath: string + ]; + 'view/stage/abstract/elementToolbar/button/newElement/clicked': readonly [ + targetEvent: 'view/insertElements/perform/after' | 'view/insertElements/perform/inside', + modalConfiguration: InsertElementsModalConfiguration + ]; + // triggered by 'view/stage/abstract/elementToolbar/button/newElement/clicked' via + // ModalComponent.insertElementsModalSetup() + 'view/insertElements/perform/after': readonly [ + formElementType: string + ]; + // triggered by 'view/stage/abstract/elementToolbar/button/newElement/clicked' via + // ModalComponent.insertElementsModalSetup() + 'view/insertElements/perform/inside': readonly [ + formElementType: string + ]; + } +} diff --git a/typo3/sysext/form/Resources/Public/JavaScript/backend/form-editor/stage-component.js b/typo3/sysext/form/Resources/Public/JavaScript/backend/form-editor/stage-component.js index b5eefdeea23d15775d2d7cdbcdf13f6b9c6af0e6..cc413f817c14abb04f917c17bceb4cdd4a146d91 100644 --- a/typo3/sysext/form/Resources/Public/JavaScript/backend/form-editor/stage-component.js +++ b/typo3/sysext/form/Resources/Public/JavaScript/backend/form-editor/stage-component.js @@ -10,1200 +10,4 @@ * * The TYPO3 project - inspiring people to share! */ - -/** - * Module: @typo3/form/backend/form-editor/stage-component - */ -import $ from 'jquery'; -import * as Helper from '@typo3/form/backend/form-editor/helper.js'; -import Icons from '@typo3/backend/icons.js'; -import Sortable from 'sortablejs'; - -const { - bootstrap, - buildTitleByFormElement, - createAndAddAbstractViewFormElementToolbar, - createAbstractViewFormElementToolbar, - eachTemplateProperty, - getAbstractViewFormElementDomElement, - getAbstractViewFormElementWithinDomElement, - getAbstractViewFormElementIdentifierPathWithinDomElement, - getAbstractViewParentFormElementWithinDomElement, - getAbstractViewParentFormElementIdentifierPathWithinDomElement, - getAbstractViewSiblingFormElementIdentifierPathWithinDomElement, - getAllFormElementDomElements, - getStageDomElement, - getStagePanelDomElement, - removeAllStageToolbars, - renderAbstractStageArea, - renderCheckboxTemplate, - renderFileUploadTemplates, - renderFormDefinitionPageAsSortableList, - renderPagination, - renderPreviewStageArea, - renderSelectTemplates, - renderSimpleTemplate, - renderSimpleTemplateWithValidators, - renderUndoRedo, - setStageHeadline, -} = factory($, Helper, Icons); - -export { - bootstrap, - buildTitleByFormElement, - createAndAddAbstractViewFormElementToolbar, - createAbstractViewFormElementToolbar, - eachTemplateProperty, - getAbstractViewFormElementDomElement, - getAbstractViewFormElementWithinDomElement, - getAbstractViewFormElementIdentifierPathWithinDomElement, - getAbstractViewParentFormElementWithinDomElement, - getAbstractViewParentFormElementIdentifierPathWithinDomElement, - getAbstractViewSiblingFormElementIdentifierPathWithinDomElement, - getAllFormElementDomElements, - getStageDomElement, - getStagePanelDomElement, - removeAllStageToolbars, - renderAbstractStageArea, - renderCheckboxTemplate, - renderFileUploadTemplates, - renderFormDefinitionPageAsSortableList, - renderPagination, - renderPreviewStageArea, - renderSelectTemplates, - renderSimpleTemplate, - renderSimpleTemplateWithValidators, - renderUndoRedo, - setStageHeadline, -}; - - -function factory($, Helper, Icons) { - return (function($, Helper, Icons) { - - /** - * @private - * - * @var object - */ - var _configuration = null; - - /** - * @private - * - * @var object - */ - var _defaultConfiguration = { - domElementClassNames: { - formElementIsComposit: 't3-form-element-composit', - formElementIsTopLevel: 't3-form-element-toplevel', - noNesting: 'mjs-nestedSortable-no-nesting', - selected: 'selected', - sortable: 'sortable', - previewViewPreviewElement: 't3-form-element-preview' - }, - domElementDataAttributeNames: { - abstractType: 'data-element-abstract-type', - noSorting: 'data-no-sorting' - }, - domElementDataAttributeValues: { - abstractViewToolbar: 'elementToolbar', - abstractViewToolbarNewElement: 'stageElementToolbarNewElement', - abstractViewToolbarNewElementSplitButton: 'stageElementToolbarNewElementSplitButton', - abstractViewToolbarNewElementSplitButtonAfter: 'stageElementToolbarNewElementSplitButtonAfter', - abstractViewToolbarNewElementSplitButtonInside: 'stageElementToolbarNewElementSplitButtonInside', - abstractViewToolbarRemoveElement: 'stageElementToolbarRemoveElement', - buttonHeaderRedo: 'redoButton', - buttonHeaderUndo: 'undoButton', - buttonPaginationPrevious: 'buttonPaginationPrevious', - buttonPaginationNext: 'buttonPaginationNext', - 'FormElement-_ElementToolbar': 'FormElement-_ElementToolbar', - 'FormElement-_UnknownElement': 'FormElement-_UnknownElement', - 'FormElement-AdvancedPassword': 'FormElement-AdvancedPassword', - 'FormElement-Checkbox': 'FormElement-Checkbox', - 'FormElement-ContentElement': 'FormElement-ContentElement', - 'FormElement-CountrySelect': 'FormElement-CountrySelect', - 'FormElement-DatePicker': 'FormElement-DatePicker', - 'FormElement-Fieldset': 'FormElement-Fieldset', - 'FormElement-GridRow': 'FormElement-GridRow', - 'FormElement-FileUpload': 'FormElement-FileUpload', - 'FormElement-Hidden': 'FormElement-Hidden', - 'FormElement-ImageUpload': 'FormElement-ImageUpload', - 'FormElement-MultiCheckbox': 'FormElement-MultiCheckbox', - 'FormElement-MultiSelect': 'FormElement-MultiSelect', - 'FormElement-Page': 'FormElement-Page', - 'FormElement-Password': 'FormElement-Password', - 'FormElement-RadioButton': 'FormElement-RadioButton', - 'FormElement-SingleSelect': 'FormElement-SingleSelect', - 'FormElement-StaticText': 'FormElement-StaticText', - 'FormElement-SummaryPage': 'FormElement-SummaryPage', - 'FormElement-Text': 'FormElement-Text', - 'FormElement-Textarea': 'FormElement-Textarea', - 'FormElement-Email': 'FormElement-Email', - 'FormElement-Url': 'FormElement-Url', - 'FormElement-Telephone': 'FormElement-Telephone', - 'FormElement-Number': 'FormElement-Number', - 'FormElement-Date': 'FormElement-Date', - formElementIcon: 'elementIcon', - iconValidator: 'form-validator', - multiValueContainer: 'multiValueContainer', - paginationTitle: 'paginationTitle', - stageHeadline: 'formDefinitionLabel', - stagePanel: 'stagePanel', - validatorsContainer: 'validatorsContainer', - validatorIcon: 'validatorIcon' - }, - isSortable: true - }; - - /** - * @private - * - * @var object - */ - var _formEditorApp = null; - - /** - * @private - * - * @var object - */ - var _stageDomElement = null; - - /* ************************************************************* - * Private Methods - * ************************************************************/ - - /** - * @private - * - * @return void - * @throws 1478268638 - */ - function _helperSetup() { - assert('function' === $.type(Helper.bootstrap), - 'The view model helper does not implement the method "bootstrap"', - 1478268638 - ); - Helper.bootstrap(getFormEditorApp()); - }; - - /** - * @private - * - * @return object - */ - function getFormEditorApp() { - return _formEditorApp; - }; - - /** - * @public - * - * @param object - * @return object - */ - function getHelper(configuration) { - if (getUtility().isUndefinedOrNull(configuration)) { - return Helper.setConfiguration(_configuration); - } - return Helper.setConfiguration(configuration); - }; - - /** - * @private - * - * @return object - */ - function getUtility() { - return getFormEditorApp().getUtility(); - }; - - /** - * @private - * - * @return object - */ - function getViewModel() { - return getFormEditorApp().getViewModel(); - }; - - /** - * @private - * - * @param mixed test - * @param string message - * @param int messageCode - * @return void - */ - function assert(test, message, messageCode) { - return getFormEditorApp().assert(test, message, messageCode); - }; - - /** - * @private - * - * @return object - */ - function getRootFormElement() { - return getFormEditorApp().getRootFormElement(); - }; - - /** - * @private - * - * @return object - */ - function getCurrentlySelectedFormElement() { - return getFormEditorApp().getCurrentlySelectedFormElement(); - }; - - /** - * @private - * - * @return object - */ - function getPublisherSubscriber() { - return getFormEditorApp().getPublisherSubscriber(); - }; - - /** - * @private - * - * @param object - * @param string - * @return mixed - */ - function getFormElementDefinition(formElement, formElementDefinitionKey) { - return getFormEditorApp().getFormElementDefinition(formElement, formElementDefinitionKey); - }; - - /** - * @private - * - * @return object - * @return string - * @return void - */ - function _setTemplateTextContent(domElement, content) { - if (getUtility().isNonEmptyString(content)) { - $(domElement).text(content); - } - } - - /** - * @private - * - * @param object - * @param object - * @return void - * @publish view/stage/abstract/render/template/perform - */ - function _renderTemplateDispatcher(formElement, template) { - switch (formElement.get('type')) { - case 'Checkbox': - renderCheckboxTemplate(formElement, template); - break; - case 'FileUpload': - case 'ImageUpload': - renderFileUploadTemplates(formElement, template); - break; - case 'CountrySelect': - case 'SingleSelect': - case 'RadioButton': - case 'MultiSelect': - case 'MultiCheckbox': - renderSelectTemplates(formElement, template); - break; - case 'Textarea': - case 'AdvancedPassword': - case 'Password': - case 'Text': - case 'Email': - case 'Url': - case 'Telephone': - case 'Number': - case 'DatePicker': - case 'Date': - renderSimpleTemplateWithValidators(formElement, template); - break; - case 'Fieldset': - case 'GridRow': - case 'SummaryPage': - case 'Page': - case 'StaticText': - case 'Hidden': - case 'ContentElement': - renderSimpleTemplate(formElement, template); - break; - } - getPublisherSubscriber().publish('view/stage/abstract/render/template/perform', [formElement, template]); - }; - - /** - * @private - * - * @param object - * @return object - * @throws 1478987818 - */ - function _renderNestedSortableListItem(formElement) { - var childFormElements, childList, listItem, template; - - listItem = $('<li></li>'); - if (!getFormElementDefinition(formElement, '_isCompositeFormElement')) { - listItem.addClass(getHelper().getDomElementClassName('noNesting')); - } - - if (getFormElementDefinition(formElement, '_isTopLevelFormElement')) { - listItem.addClass(getHelper().getDomElementClassName('formElementIsTopLevel')); - } - if (getFormElementDefinition(formElement, '_isCompositeFormElement')) { - listItem.addClass(getHelper().getDomElementClassName('formElementIsComposit')); - } - - try { - template = getHelper().getTemplate('FormElement-' + formElement.get('type')).clone(); - } catch (error) { - template = getHelper().getTemplate('FormElement-_UnknownElement').clone(); - assert( - template.length, - 'No template found for element "' + formElement.get('__identifierPath') + '"', - 1478987818 - ); - } - - template = $('<div></div>') - .attr(getHelper().getDomElementDataAttribute('elementIdentifier'), formElement.get('__identifierPath')) - .append($(template.html())); - - if (getFormElementDefinition(formElement, '_isCompositeFormElement')) { - template.attr(getHelper().getDomElementDataAttribute('abstractType'), 'isCompositeFormElement'); - } - if (getFormElementDefinition(formElement, '_isTopLevelFormElement')) { - template.attr(getHelper().getDomElementDataAttribute('abstractType'), 'isTopLevelFormElement'); - } - listItem.append(template); - - _renderTemplateDispatcher(formElement, template); - - childFormElements = formElement.get('renderables'); - childList = null; - if ('array' === $.type(childFormElements)) { - childList = $('<ol></ol>'); - childList.addClass(getHelper().getDomElementClassName('sortable')); - for (var i = 0, len = childFormElements.length; i < len; ++i) { - childList.append(_renderNestedSortableListItem(childFormElements[i])); - } - } - - if (childList) { - listItem.append(childList); - } - return listItem; - }; - - /** - * @private - * - * @return void - * @publish view/stage/abstract/dnd/start - * @publish view/stage/abstract/dnd/stop - * @publish view/stage/abstract/dnd/change - * @publish view/stage/abstract/dnd/update - */ - function _addSortableEvents() { - const sortableLists = _stageDomElement.get(0).querySelectorAll('ol.' + getHelper().getDomElementClassName('sortable')); - const draggableSelector = 'li:not(' + getHelper().getDomElementDataAttribute('noSorting', 'bracesWithKey') + ')'; - const handleSelector = 'div' + getHelper().getDomElementDataAttribute('elementIdentifier', 'bracesWithKey'); - - sortableLists.forEach(function (sortableList) { - sortableList.querySelectorAll(handleSelector).forEach(function (draggable) { - draggable.classList.add('form-sortable-handle'); - }); - - new Sortable(sortableList, { - group: 'stage-nodes', - handle: handleSelector, - draggable: draggableSelector, - animation: 200, - swapThreshold: 0.6, - dragClass: 'form-sortable-drag', - ghostClass: 'form-sortable-ghost', - onStart: function (e) { - getPublisherSubscriber().publish('view/stage/abstract/dnd/start', [$(e.item), $(e.item)]); - }, - onChange: function (e) { - let enclosingCompositeFormElement; - const parentFormElementIdentifierPath = getAbstractViewParentFormElementIdentifierPathWithinDomElement($(e.item)); - - if (parentFormElementIdentifierPath) { - enclosingCompositeFormElement = getFormEditorApp() - .findEnclosingCompositeFormElementWhichIsNotOnTopLevel(parentFormElementIdentifierPath); - } - getPublisherSubscriber().publish('view/stage/abstract/dnd/change', [ - $(e.item), - parentFormElementIdentifierPath, enclosingCompositeFormElement - ]); - }, - onEnd: function (e) { - const movedFormElementIdentifierPath = getAbstractViewFormElementIdentifierPathWithinDomElement($(e.item)); - const previousFormElementIdentifierPath = getAbstractViewSiblingFormElementIdentifierPathWithinDomElement($(e.item), 'prev'); - const nextFormElementIdentifierPath = getAbstractViewSiblingFormElementIdentifierPathWithinDomElement($(e.item), 'next'); - - getPublisherSubscriber().publish('view/stage/abstract/dnd/update', [ - $(e.item), - movedFormElementIdentifierPath, - previousFormElementIdentifierPath, - nextFormElementIdentifierPath - ]); - getPublisherSubscriber().publish('view/stage/abstract/dnd/stop', [ - getAbstractViewFormElementIdentifierPathWithinDomElement($(e.item)) - ]); - }, - }); - }); - }; - - /* ************************************************************* - * Public Methods - * ************************************************************/ - - /** - * @public - * - * @return object - */ - function getStageDomElement() { - return _stageDomElement; - }; - - /** - * @public - * - * @param object - * @return object - * @throws 1479037151 - */ - function buildTitleByFormElement(formElement) { - if (getUtility().isUndefinedOrNull(formElement)) { - formElement = getRootFormElement(); - } - assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1479037151); - - return $('<span></span>') - .text((formElement.get('label') ? formElement.get('label') : formElement.get('identifier'))); - }; - - /** - * @public - * - * @param string title - * @return void - */ - function setStageHeadline(title) { - if (getUtility().isUndefinedOrNull(title)) { - title = buildTitleByFormElement().text(); - } - - $(getHelper().getDomElementDataIdentifierSelector('stageHeadline')).text(title); - }; - - /** - * @public - * - * @return object - */ - function getStagePanelDomElement() { - return $(getHelper().getDomElementDataIdentifierSelector('stagePanel')); - }; - - /** - * @public - * - * @return void - */ - function renderPagination() { - var pageCount; - - pageCount = getRootFormElement().get('renderables').length; - - getViewModel().enableButton($(getHelper().getDomElementDataIdentifierSelector('buttonPaginationPrevious'))); - getViewModel().enableButton($(getHelper().getDomElementDataIdentifierSelector('buttonPaginationNext'))); - - if (getFormEditorApp().getCurrentlySelectedPageIndex() === 0) { - getViewModel().disableButton($(getHelper().getDomElementDataIdentifierSelector('buttonPaginationPrevious'))); - } - - if (pageCount === 1 || getFormEditorApp().getCurrentlySelectedPageIndex() === (pageCount - 1)) { - getViewModel().disableButton($(getHelper().getDomElementDataIdentifierSelector('buttonPaginationNext'))); - } - - $(getHelper().getDomElementDataIdentifierSelector('paginationTitle')).text( - getFormElementDefinition(getRootFormElement(), 'paginationTitle') - .replace('{0}', getFormEditorApp().getCurrentlySelectedPageIndex() + 1) - .replace('{1}', pageCount) - ); - }; - - /** - * @public - * - * @return void - */ - function renderUndoRedo() { - getViewModel().enableButton($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderUndo'))); - getViewModel().enableButton($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderRedo'))); - - if (getFormEditorApp().getCurrentApplicationStatePosition() + 1 >= getFormEditorApp().getCurrentApplicationStates()) { - getViewModel().disableButton($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderUndo'))); - } - if (getFormEditorApp().getCurrentApplicationStatePosition() === 0) { - getViewModel().disableButton($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderRedo'))); - } - }; - - /** - * @public - * - * @param object - * @return string - */ - function getAllFormElementDomElements() { - return $(getHelper().getDomElementDataAttribute('elementIdentifier', 'bracesWithKey'), - _stageDomElement - ); - }; - - /* ************************************************************* - * Abstract stage - * ************************************************************/ - - /** - * @public - * - * @param int - * @return object - * @throws 1478721208 - */ - function renderFormDefinitionPageAsSortableList(pageIndex) { - assert( - 'number' === $.type(pageIndex), - 'Invalid parameter "pageIndex"', - 1478721208 - ); - - return $('<ol></ol>') - .append(_renderNestedSortableListItem(getRootFormElement().get('renderables')[pageIndex])); - }; - - /** - * @public - * - * @param object - * @return string - */ - function getAbstractViewParentFormElementWithinDomElement(element) { - return $(element) - .parent() - .closest('li') - .find(getHelper().getDomElementDataAttribute('elementIdentifier', 'bracesWithKey')) - .first(); - }; - - /** - * @public - * - * @param object - * @return string - */ - function getAbstractViewParentFormElementIdentifierPathWithinDomElement(element) { - return getAbstractViewParentFormElementWithinDomElement(element) - .attr(getHelper().getDomElementDataAttribute('elementIdentifier')); - }; - - /** - * @public - * - * @param object - * @return string - */ - function getAbstractViewFormElementWithinDomElement(element) { - return $(element) - .find(getHelper().getDomElementDataAttribute('elementIdentifier', 'bracesWithKey')) - .first(); - }; - - /** - * @public - * - * @param object - * @return string - */ - function getAbstractViewFormElementIdentifierPathWithinDomElement(element) { - return getAbstractViewFormElementWithinDomElement($(element)) - .attr(getHelper().getDomElementDataAttribute('elementIdentifier')); - }; - - /** - * @private - * - * @param object - * @param string - * @return string - */ - function getAbstractViewSiblingFormElementIdentifierPathWithinDomElement(element, position) { - var formElementIdentifierPath; - - if (getUtility().isUndefinedOrNull(position)) { - position = 'prev'; - } - formElementIdentifierPath = getAbstractViewFormElementIdentifierPathWithinDomElement(element); - element = (position === 'prev') ? $(element).prev('li') : $(element).next('li'); - return element.find(getHelper().getDomElementDataAttribute('elementIdentifier', 'bracesWithKey')) - .not(getHelper().getDomElementDataAttribute('elementIdentifier', 'bracesWithKeyValue', [formElementIdentifierPath])) - .first() - .attr(getHelper().getDomElementDataAttribute('elementIdentifier')); - }; - - /** - * @public - * - * @param string|object - * @return object - */ - function getAbstractViewFormElementDomElement(formElement) { - var formElementIdentifierPath; - - if ('string' === $.type(formElement)) { - formElementIdentifierPath = formElement; - } else { - if (getUtility().isUndefinedOrNull(formElement)) { - formElementIdentifierPath = getCurrentlySelectedFormElement().get('__identifierPath'); - } else { - formElementIdentifierPath = formElement.get('__identifierPath'); - } - } - return $(getHelper() - .getDomElementDataAttribute('elementIdentifier', 'bracesWithKeyValue', [formElementIdentifierPath]), _stageDomElement); - }; - - /** - * @public - * - * @return void - */ - function removeAllStageToolbars() { - $(getHelper().getDomElementDataIdentifierSelector('abstractViewToolbar'), _stageDomElement).off().empty().remove(); - }; - - /** - * @public - * - * @param object - * @return object - * @publish view/insertElements/perform/after - * @publish view/insertElements/perform/inside - * @throws 1479035778 - */ - function createAbstractViewFormElementToolbar(formElement) { - var formElementTypeDefinition, template; - assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1479035778); - - formElementTypeDefinition = getFormElementDefinition(formElement); - if (formElementTypeDefinition['_isTopLevelFormElement']) { - return $(); - } - - template = getHelper().getTemplate('FormElement-_ElementToolbar').clone(); - if (!template.length) { - return $(); - } - - template = $($(template.html())); - - getHelper().getTemplatePropertyDomElement('_type', template).text(getFormElementDefinition(formElement, 'label')); - getHelper().getTemplatePropertyDomElement('_identifier', template).text(formElement.get('identifier')); - - if (formElementTypeDefinition['_isCompositeFormElement']) { - getViewModel().hideComponent($(getHelper().getDomElementDataIdentifierSelector('abstractViewToolbarNewElement'), template)); - - $(getHelper().getDomElementDataIdentifierSelector('abstractViewToolbarNewElementSplitButtonAfter'), template).on('click', function(e) { - getPublisherSubscriber().publish('view/stage/abstract/elementToolbar/button/newElement/clicked', [ - 'view/insertElements/perform/after', - { - disableElementTypes: [], - onlyEnableElementTypes: [] - } - ] - ); - }); - - $(getHelper().getDomElementDataIdentifierSelector('abstractViewToolbarNewElementSplitButtonInside'), template).on('click', function(e) { - getPublisherSubscriber().publish('view/stage/abstract/elementToolbar/button/newElement/clicked', [ - 'view/insertElements/perform/inside', - { - disableElementTypes: [], - onlyEnableElementTypes: [] - } - ] - ); - }); - } else { - getViewModel().hideComponent($(getHelper().getDomElementDataIdentifierSelector('abstractViewToolbarNewElementSplitButton'), template)); - - $(getHelper().getDomElementDataIdentifierSelector('abstractViewToolbarNewElement'), template).on('click', function(e) { - getPublisherSubscriber().publish( - 'view/stage/abstract/elementToolbar/button/newElement/clicked', [ - 'view/insertElements/perform/after', - { - disableElementTypes: [] - } - ] - ); - }); - } - - $(getHelper().getDomElementDataIdentifierSelector('abstractViewToolbarRemoveElement'), template).on('click', function(e) { - getViewModel().showRemoveFormElementModal(); - }); - - return template; - }; - - /** - * @public - * - * @param object - * @param object - * @param bool - * @return void - */ - function createAndAddAbstractViewFormElementToolbar(selectedFormElementDomElement, formElement, useFadeEffect) { - var toolbar; - if (getUtility().isUndefinedOrNull(formElement)) { - formElement = getCurrentlySelectedFormElement(); - } - - if (useFadeEffect) { - createAbstractViewFormElementToolbar(formElement).fadeOut(0, function() { - selectedFormElementDomElement.prepend($(this)); - $(getHelper().getDomElementDataIdentifierSelector('abstractViewToolbar'), selectedFormElementDomElement).fadeIn('fast'); - }); - } else { - selectedFormElementDomElement.prepend(createAbstractViewFormElementToolbar(formElement)); - } - - }; - - /** - * @public - * - * @param int - * @param function - * @return void - * @publish view/stage/dnd/stop - * @publish view/stage/element/clicked - * @throws 1478169511 - */ - function renderAbstractStageArea(pageIndex, callback) { - if (getUtility().isUndefinedOrNull(pageIndex)) { - pageIndex = getFormEditorApp().getCurrentlySelectedPageIndex(); - } - _stageDomElement.off().empty().append(renderFormDefinitionPageAsSortableList(pageIndex)); - - _stageDomElement.on("click", function(e) { - var formElementIdentifierPath; - - formElementIdentifierPath = $(e.target) - .closest(getHelper().getDomElementDataAttribute('elementIdentifier', 'bracesWithKey')) - .attr(getHelper().getDomElementDataAttribute('elementIdentifier')); - if ( - getUtility().isUndefinedOrNull(formElementIdentifierPath) - || !getUtility().isNonEmptyString(formElementIdentifierPath) - ) { - return; - } - - getPublisherSubscriber().publish('view/stage/element/clicked', [formElementIdentifierPath]); - }); - - if (_configuration['isSortable']) { - _addSortableEvents(); - } - - if ('function' === $.type(callback)) { - callback(); - } - }; - - - /* ************************************************************* - * Preview stage - * ************************************************************/ - - /** - * @public - * - * @param string html - * @return void - * @throws 1475424409 - */ - function renderPreviewStageArea(html) { - assert(getUtility().isNonEmptyString(html), 'Invalid parameter "html"', 1475424409); - - _stageDomElement.off().empty().html(html); - - $(':input', _stageDomElement).prop('disabled', 'disabled').on('click dblclick select focus keydown keypress keyup mousedown mouseup', function(e) { - return e.preventDefault(); - }); - - $('form', _stageDomElement).submit(function(e) { - return e.preventDefault(); - }); - - getAllFormElementDomElements().each(function(i, element) { - var formElement, metaLabel; - - formElement = getFormEditorApp() - .getFormElementByIdentifierPath($(this).data('elementIdentifierPath')); - - if ( - !getFormElementDefinition(formElement, '_isTopLevelFormElement') - ) { - $(this).attr('title', 'identifier: ' + formElement.get('identifier') + ' (type: ' + formElement.get('type') + ')'); - } - - if (getFormElementDefinition(formElement, '_isTopLevelFormElement')) { - $(this).addClass(getHelper().getDomElementClassName('formElementIsTopLevel')); - } - if (getFormElementDefinition(formElement, '_isCompositeFormElement')) { - $(this).addClass(getHelper().getDomElementClassName('formElementIsComposit')); - } - }); - - }; - - /* ************************************************************* - * Template rendering - * ************************************************************/ - - /** - * @public - * - * @param object - * @param template - * @param function - * @return void - */ - function eachTemplateProperty(formElement, template, callback) { - $(getHelper().getDomElementDataAttribute('templateProperty', 'bracesWithKey'), template).each(function(i, element) { - var propertyPath, propertyValue; - - propertyPath = $(element).attr(getHelper().getDomElementDataAttribute('templateProperty')); - propertyValue = formElement.get(propertyPath); - - if ('function' === $.type(callback)) { - callback(propertyPath, propertyValue, element); - } - }); - }; - - /** - * @private - * - * @return object - * @return object - * @return void - */ - function renderCheckboxTemplate(formElement, template) { - renderSimpleTemplateWithValidators(formElement, template); - - eachTemplateProperty(formElement, template, function(propertyPath, propertyValue, domElement) { - if ( - ('boolean' === $.type(propertyValue) && propertyValue) - || propertyValue === 'true' - || propertyValue === 1 - || propertyValue === "1" - ) { - $(domElement).addClass(getHelper().getDomElementClassName('noNesting')); - } - }); - }; - - /** - * @public - * - * @return object - * @return object - * @return void - * @throws 1479035696 - */ - function renderSimpleTemplate(formElement, template) { - assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1479035696); - - eachTemplateProperty(formElement, template, function(propertyPath, propertyValue, domElement) { - _setTemplateTextContent(domElement, propertyValue); - }); - - Icons.getIcon( - getFormElementDefinition(formElement, 'iconIdentifier'), - Icons.sizes.small, - null, - Icons.states.default, - Icons.markupIdentifiers.inline - ).then(function(icon) { - $(getHelper().getDomElementDataIdentifierSelector('formElementIcon'), template) - .append($(icon).addClass(getHelper().getDomElementClassName('icon'))); - }); - - getHelper() - .getTemplatePropertyDomElement('_type', template) - .append(document.createTextNode(getFormElementDefinition(formElement, 'label'))); - getHelper() - .getTemplatePropertyDomElement('_identifier', template) - .append(document.createTextNode(formElement.get('identifier'))); - }; - - /** - * @public - * - * @return object - * @return object - * @return void - * @throws 1479035674 - */ - function renderSimpleTemplateWithValidators(formElement, template) { - var validators, validatorsCountWithoutRequired, validatorsTemplateContent; - assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1479035674); - - renderSimpleTemplate(formElement, template); - - validatorsTemplateContent = $( - getHelper().getDomElementDataIdentifierSelector('validatorsContainer'), - $(template) - ).clone(); - - $(getHelper().getDomElementDataIdentifierSelector('validatorsContainer'), $(template)).empty(); - validators = formElement.get('validators'); - - if ('array' === $.type(validators)) { - validatorsCountWithoutRequired = 0; - if (validators.length > 0) { - for (var i = 0, len = validators.length; i < len; ++i) { - var collectionElementConfiguration, rowTemplate; - - if ('NotEmpty' === validators[i]['identifier']) { - getHelper() - .getTemplatePropertyDomElement('_required', template) - .text('*'); - continue; - } - validatorsCountWithoutRequired++; - - collectionElementConfiguration = getFormEditorApp() - .getFormEditorDefinition('validators', validators[i]['identifier']); - rowTemplate = $($(validatorsTemplateContent).clone()); - - getHelper() - .getTemplatePropertyDomElement('_label', rowTemplate) - .append(document.createTextNode(collectionElementConfiguration['label'])); - $(getHelper().getDomElementDataIdentifierSelector('validatorsContainer'), $(template)) - .append(rowTemplate.html()); - } - - if (validatorsCountWithoutRequired > 0) { - Icons.getIcon( - getHelper().getDomElementDataAttributeValue('iconValidator'), - Icons.sizes.small, - null, - Icons.states.default, - Icons.markupIdentifiers.inline - ).then(function(icon) { - $(getHelper().getDomElementDataIdentifierSelector('validatorIcon'), $(template)) - .append($(icon).addClass(getHelper().getDomElementClassName('icon'))); - }); - } - } - } - }; - - /** - * @public - * - * @return object - * @return object - * @return void - */ - function renderSelectTemplates(formElement, template) { - var appendMultiValue, defaultValue, multiValueTemplateContent, propertyPath, propertyValue; - - multiValueTemplateContent = $( - getHelper().getDomElementDataIdentifierSelector('multiValueContainer'), - $(template) - ).clone(); - $(getHelper().getDomElementDataIdentifierSelector('multiValueContainer'), $(template)).empty(); - - renderSimpleTemplateWithValidators(formElement, template); - - propertyPath = $(getHelper().getDomElementDataIdentifierSelector('multiValueContainer'), $(template)) - .attr(getHelper().getDomElementDataAttribute('templateProperty')); - - propertyValue = formElement.get(propertyPath); - - appendMultiValue = function(label, value, defaultValue) { - var isPreselected, rowTemplate; - - isPreselected = false; - rowTemplate = $($(multiValueTemplateContent).clone()); - - for (var defaultValueKey in defaultValue) { - if (!defaultValue.hasOwnProperty(defaultValueKey)) { - continue; - } - if (defaultValue[defaultValueKey] === value) { - isPreselected = true; - break; - } - } - - getHelper().getTemplatePropertyDomElement('_label', rowTemplate).append(document.createTextNode(label)); - - if (isPreselected) { - getHelper().getTemplatePropertyDomElement('_label', rowTemplate).addClass( - getHelper().getDomElementClassName('selected') - ); - } - - $(getHelper().getDomElementDataIdentifierSelector('multiValueContainer'), $(template)) - .append(rowTemplate.html()); - }; - - defaultValue = formElement.get('defaultValue'); - - if (getFormEditorApp().getUtility().isUndefinedOrNull(defaultValue)) { - defaultValue = {}; - } else if ('string' === $.type(defaultValue)) { - defaultValue = {0: defaultValue}; - } - - if ('object' === $.type(propertyValue)) { - for (var propertyValueKey in propertyValue) { - if (!propertyValue.hasOwnProperty(propertyValueKey)) { - continue; - } - appendMultiValue(propertyValue[propertyValueKey], propertyValueKey, defaultValue); - } - } else if ('array' === $.type(propertyValue)) { - for (var propertyValueKey in propertyValue) { - if (!propertyValue.hasOwnProperty(propertyValueKey)) { - continue; - } - if (getUtility().isUndefinedOrNull(propertyValue[propertyValueKey]['_label'])) { - appendMultiValue(propertyValue[propertyValueKey], propertyValueKey, defaultValue); - } else { - appendMultiValue(propertyValue[propertyValueKey]['_label'], propertyValue[propertyValueKey]['_value'], defaultValue); - } - } - } - }; - - /** - * @public - * - * @return object - * @return object - * @return void - */ - function renderFileUploadTemplates(formElement, template) { - var appendMultiValue, multiValueTemplateContent, propertyPath, propertyValue; - - multiValueTemplateContent = $( - getHelper().getDomElementDataIdentifierSelector('multiValueContainer'), - $(template) - ).clone(); - $(getHelper().getDomElementDataIdentifierSelector('multiValueContainer'), $(template)).empty(); - - renderSimpleTemplateWithValidators(formElement, template); - - propertyPath = $(getHelper().getDomElementDataIdentifierSelector('multiValueContainer'), $(template)) - .attr(getHelper().getDomElementDataAttribute('templateProperty')); - propertyValue = formElement.get(propertyPath); - - appendMultiValue = function(value) { - var rowTemplate; - - rowTemplate = $($(multiValueTemplateContent).clone()); - - getHelper().getTemplatePropertyDomElement('_value', rowTemplate).append(value); - $(getHelper().getDomElementDataIdentifierSelector('multiValueContainer'), $(template)) - .append(rowTemplate.html()); - }; - - if ('object' === $.type(propertyValue)) { - for (var propertyValueKey in propertyValue) { - if (!propertyValue.hasOwnProperty(propertyValueKey)) { - continue; - } - appendMultiValue(propertyValue[propertyValueKey]); - } - } else if ('array' === $.type(propertyValue)) { - for (var i = 0, len = propertyValue.length; i < len; ++i) { - appendMultiValue(propertyValue[i]); - } - } - }; - - /** - * @public - * - * @param object - * @param object - * @param object - * @return this - * @throws 1478992119 - */ - function bootstrap(formEditorApp, appendToDomElement, configuration) { - _formEditorApp = formEditorApp; - assert('object' === $.type(appendToDomElement), 'Invalid parameter "appendToDomElement"', 1478992119); - - _stageDomElement = $(appendToDomElement); - _configuration = $.extend(true, _defaultConfiguration, configuration || {}); - _helperSetup(); - return this; - }; - - /** - * Publish the public methods. - * Implements the "Revealing Module Pattern". - */ - return { - bootstrap: bootstrap, - buildTitleByFormElement: buildTitleByFormElement, - createAndAddAbstractViewFormElementToolbar: createAndAddAbstractViewFormElementToolbar, - createAbstractViewFormElementToolbar: createAbstractViewFormElementToolbar, - eachTemplateProperty: eachTemplateProperty, - getAbstractViewFormElementDomElement: getAbstractViewFormElementDomElement, - getAbstractViewFormElementWithinDomElement: getAbstractViewFormElementWithinDomElement, - getAbstractViewFormElementIdentifierPathWithinDomElement: getAbstractViewFormElementIdentifierPathWithinDomElement, - getAbstractViewParentFormElementWithinDomElement: getAbstractViewParentFormElementWithinDomElement, - getAbstractViewParentFormElementIdentifierPathWithinDomElement: getAbstractViewParentFormElementIdentifierPathWithinDomElement, - getAbstractViewSiblingFormElementIdentifierPathWithinDomElement: getAbstractViewSiblingFormElementIdentifierPathWithinDomElement, - getAllFormElementDomElements: getAllFormElementDomElements, - getStageDomElement: getStageDomElement, - getStagePanelDomElement: getStagePanelDomElement, - removeAllStageToolbars: removeAllStageToolbars, - renderAbstractStageArea: renderAbstractStageArea, - renderCheckboxTemplate: renderCheckboxTemplate, - renderFileUploadTemplates: renderFileUploadTemplates, - renderFormDefinitionPageAsSortableList: renderFormDefinitionPageAsSortableList, - renderPagination: renderPagination, - renderPreviewStageArea: renderPreviewStageArea, - renderSelectTemplates: renderSelectTemplates, - renderSimpleTemplate: renderSimpleTemplate, - renderSimpleTemplateWithValidators: renderSimpleTemplateWithValidators, - renderUndoRedo: renderUndoRedo, - setStageHeadline: setStageHeadline - }; - })($, Helper, Icons); -} +import $ from"jquery";import*as Helper from"@typo3/form/backend/form-editor/helper.js";import Icons from"@typo3/backend/icons.js";import Sortable from"sortablejs";const defaultConfiguration={domElementClassNames:{formElementIsComposit:"t3-form-element-composit",formElementIsTopLevel:"t3-form-element-toplevel",noNesting:"mjs-nestedSortable-no-nesting",selected:"selected",sortable:"sortable",previewViewPreviewElement:"t3-form-element-preview"},domElementDataAttributeNames:{abstractType:"data-element-abstract-type",noSorting:"data-no-sorting"},domElementDataAttributeValues:{abstractViewToolbar:"elementToolbar",abstractViewToolbarNewElement:"stageElementToolbarNewElement",abstractViewToolbarNewElementSplitButton:"stageElementToolbarNewElementSplitButton",abstractViewToolbarNewElementSplitButtonAfter:"stageElementToolbarNewElementSplitButtonAfter",abstractViewToolbarNewElementSplitButtonInside:"stageElementToolbarNewElementSplitButtonInside",abstractViewToolbarRemoveElement:"stageElementToolbarRemoveElement",buttonHeaderRedo:"redoButton",buttonHeaderUndo:"undoButton",buttonPaginationPrevious:"buttonPaginationPrevious",buttonPaginationNext:"buttonPaginationNext","FormElement-_ElementToolbar":"FormElement-_ElementToolbar","FormElement-_UnknownElement":"FormElement-_UnknownElement","FormElement-AdvancedPassword":"FormElement-AdvancedPassword","FormElement-Checkbox":"FormElement-Checkbox","FormElement-ContentElement":"FormElement-ContentElement","FormElement-CountrySelect":"FormElement-CountrySelect","FormElement-DatePicker":"FormElement-DatePicker","FormElement-Fieldset":"FormElement-Fieldset","FormElement-GridRow":"FormElement-GridRow","FormElement-FileUpload":"FormElement-FileUpload","FormElement-Hidden":"FormElement-Hidden","FormElement-ImageUpload":"FormElement-ImageUpload","FormElement-MultiCheckbox":"FormElement-MultiCheckbox","FormElement-MultiSelect":"FormElement-MultiSelect","FormElement-Page":"FormElement-Page","FormElement-Password":"FormElement-Password","FormElement-RadioButton":"FormElement-RadioButton","FormElement-SingleSelect":"FormElement-SingleSelect","FormElement-StaticText":"FormElement-StaticText","FormElement-SummaryPage":"FormElement-SummaryPage","FormElement-Text":"FormElement-Text","FormElement-Textarea":"FormElement-Textarea","FormElement-Email":"FormElement-Email","FormElement-Url":"FormElement-Url","FormElement-Telephone":"FormElement-Telephone","FormElement-Number":"FormElement-Number","FormElement-Date":"FormElement-Date",formElementIcon:"elementIcon",iconValidator:"form-validator",multiValueContainer:"multiValueContainer",paginationTitle:"paginationTitle",stageHeadline:"formDefinitionLabel",stagePanel:"stagePanel",validatorsContainer:"validatorsContainer",validatorIcon:"validatorIcon"},isSortable:!0};let configuration=null,formEditorApp=null,stageDomElement=null;function getFormEditorApp(){return formEditorApp}function getHelper(e){return getUtility().isUndefinedOrNull(e)?Helper.setConfiguration(configuration):Helper.setConfiguration(e)}function getUtility(){return getFormEditorApp().getUtility()}function getViewModel(){return getFormEditorApp().getViewModel()}function assert(e,t,n){return getFormEditorApp().assert(e,t,n)}function getRootFormElement(){return getFormEditorApp().getRootFormElement()}function getCurrentlySelectedFormElement(){return getFormEditorApp().getCurrentlySelectedFormElement()}function getPublisherSubscriber(){return getFormEditorApp().getPublisherSubscriber()}function getFormElementDefinition(e,t){return getFormEditorApp().getFormElementDefinition(e,t)}function setTemplateTextContent(e,t){getUtility().isNonEmptyString(t)&&$(e).text(t)}function renderTemplateDispatcher(e,t){switch(e.get("type")){case"Checkbox":renderCheckboxTemplate(e,t);break;case"FileUpload":case"ImageUpload":renderFileUploadTemplates(e,t);break;case"CountrySelect":case"SingleSelect":case"RadioButton":case"MultiSelect":case"MultiCheckbox":renderSelectTemplates(e,t);break;case"Textarea":case"AdvancedPassword":case"Password":case"Text":case"Email":case"Url":case"Telephone":case"Number":case"DatePicker":case"Date":renderSimpleTemplateWithValidators(e,t);break;case"Fieldset":case"GridRow":case"SummaryPage":case"Page":case"StaticText":case"Hidden":case"ContentElement":renderSimpleTemplate(e,t)}getPublisherSubscriber().publish("view/stage/abstract/render/template/perform",[e,t])}function renderNestedSortableListItem(e){let t,n;const r=$("<li></li>");getFormElementDefinition(e,"_isCompositeFormElement")||r.addClass(getHelper().getDomElementClassName("noNesting")),getFormElementDefinition(e,"_isTopLevelFormElement")&&r.addClass(getHelper().getDomElementClassName("formElementIsTopLevel")),getFormElementDefinition(e,"_isCompositeFormElement")&&r.addClass(getHelper().getDomElementClassName("formElementIsComposit"));try{n=getHelper().getTemplate("FormElement-"+e.get("type")).clone()}catch(t){n=getHelper().getTemplate("FormElement-_UnknownElement").clone(),assert(n.length>0,'No template found for element "'+e.get("__identifierPath")+'"',1478987818)}n=$("<div></div>").attr(getHelper().getDomElementDataAttribute("elementIdentifier"),e.get("__identifierPath")).append($(n.html())),getFormElementDefinition(e,"_isCompositeFormElement")&&n.attr(getHelper().getDomElementDataAttribute("abstractType"),"isCompositeFormElement"),getFormElementDefinition(e,"_isTopLevelFormElement")&&n.attr(getHelper().getDomElementDataAttribute("abstractType"),"isTopLevelFormElement"),r.append(n),renderTemplateDispatcher(e,n);const o=e.get("renderables");if(t=null,"array"===$.type(o)){t=$("<ol></ol>"),t.addClass(getHelper().getDomElementClassName("sortable"));for(let e=0,n=o.length;e<n;++e)t.append(renderNestedSortableListItem(o[e]))}return t&&r.append(t),r}function addSortableEvents(){const e=stageDomElement.get(0).querySelectorAll("ol."+getHelper().getDomElementClassName("sortable")),t="li:not("+getHelper().getDomElementDataAttribute("noSorting","bracesWithKey")+")",n="div"+getHelper().getDomElementDataAttribute("elementIdentifier","bracesWithKey");e.forEach((function(e){e.querySelectorAll(n).forEach((function(e){e.classList.add("form-sortable-handle")})),new Sortable(e,{group:"stage-nodes",handle:n,draggable:t,animation:200,swapThreshold:.6,dragClass:"form-sortable-drag",ghostClass:"form-sortable-ghost",onStart:function(e){getPublisherSubscriber().publish("view/stage/abstract/dnd/start",[$(e.item),$(e.item)])},onChange:function(e){let t;const n=getAbstractViewParentFormElementIdentifierPathWithinDomElement($(e.item));n&&(t=getFormEditorApp().findEnclosingCompositeFormElementWhichIsNotOnTopLevel(n)),getPublisherSubscriber().publish("view/stage/abstract/dnd/change",[$(e.item),n,t])},onEnd:function(e){const t=getAbstractViewFormElementIdentifierPathWithinDomElement($(e.item)),n=getAbstractViewSiblingFormElementIdentifierPathWithinDomElement($(e.item),"prev"),r=getAbstractViewSiblingFormElementIdentifierPathWithinDomElement($(e.item),"next");getPublisherSubscriber().publish("view/stage/abstract/dnd/update",[$(e.item),t,n,r]),getPublisherSubscriber().publish("view/stage/abstract/dnd/stop",[getAbstractViewFormElementIdentifierPathWithinDomElement($(e.item))])}})}))}export function getStageDomElement(){return stageDomElement}export function buildTitleByFormElement(e){getUtility().isUndefinedOrNull(e)&&(e=getRootFormElement()),assert("object"===$.type(e),'Invalid parameter "formElement"',1479037151);const t=document.createElement("span");return t.textContent=e.get("label")?e.get("label"):e.get("identifier"),t}export function setStageHeadline(e){getUtility().isUndefinedOrNull(e)&&(e=buildTitleByFormElement().textContent),$(getHelper().getDomElementDataIdentifierSelector("stageHeadline")).text(e)}export function getStagePanelDomElement(){return $(getHelper().getDomElementDataIdentifierSelector("stagePanel"))}export function renderPagination(){const e=getRootFormElement().get("renderables").length;getViewModel().enableButton($(getHelper().getDomElementDataIdentifierSelector("buttonPaginationPrevious"))),getViewModel().enableButton($(getHelper().getDomElementDataIdentifierSelector("buttonPaginationNext"))),0===getFormEditorApp().getCurrentlySelectedPageIndex()&&getViewModel().disableButton($(getHelper().getDomElementDataIdentifierSelector("buttonPaginationPrevious"))),1!==e&&getFormEditorApp().getCurrentlySelectedPageIndex()!==e-1||getViewModel().disableButton($(getHelper().getDomElementDataIdentifierSelector("buttonPaginationNext")));const t=getFormEditorApp().getCurrentlySelectedPageIndex()+1;$(getHelper().getDomElementDataIdentifierSelector("paginationTitle")).text(getFormElementDefinition(getRootFormElement(),"paginationTitle").replace("{0}",t.toString()).replace("{1}",e))}export function renderUndoRedo(){getViewModel().enableButton($(getHelper().getDomElementDataIdentifierSelector("buttonHeaderUndo"))),getViewModel().enableButton($(getHelper().getDomElementDataIdentifierSelector("buttonHeaderRedo"))),getFormEditorApp().getCurrentApplicationStatePosition()+1>=getFormEditorApp().getCurrentApplicationStates()&&getViewModel().disableButton($(getHelper().getDomElementDataIdentifierSelector("buttonHeaderUndo"))),0===getFormEditorApp().getCurrentApplicationStatePosition()&&getViewModel().disableButton($(getHelper().getDomElementDataIdentifierSelector("buttonHeaderRedo")))}export function getAllFormElementDomElements(){return $(getHelper().getDomElementDataAttribute("elementIdentifier","bracesWithKey"),stageDomElement)}export function renderFormDefinitionPageAsSortableList(e){return assert("number"===$.type(e),'Invalid parameter "pageIndex"',1478721208),$("<ol></ol>").append(renderNestedSortableListItem(getRootFormElement().get("renderables")[e]))}export function getAbstractViewParentFormElementWithinDomElement(e){return $(e).parent().closest("li").find(getHelper().getDomElementDataAttribute("elementIdentifier","bracesWithKey")).first()}export function getAbstractViewParentFormElementIdentifierPathWithinDomElement(e){return getAbstractViewParentFormElementWithinDomElement(e).attr(getHelper().getDomElementDataAttribute("elementIdentifier"))}export function getAbstractViewFormElementWithinDomElement(e){return $(e).find(getHelper().getDomElementDataAttribute("elementIdentifier","bracesWithKey")).first()}export function getAbstractViewFormElementIdentifierPathWithinDomElement(e){return getAbstractViewFormElementWithinDomElement($(e)).attr(getHelper().getDomElementDataAttribute("elementIdentifier"))}export function getAbstractViewSiblingFormElementIdentifierPathWithinDomElement(e,t){getUtility().isUndefinedOrNull(t)&&(t="prev");const n=getAbstractViewFormElementIdentifierPathWithinDomElement(e);return(e="prev"===t?$(e).prev("li"):$(e).next("li")).find(getHelper().getDomElementDataAttribute("elementIdentifier","bracesWithKey")).not(getHelper().getDomElementDataAttribute("elementIdentifier","bracesWithKeyValue",[n])).first().attr(getHelper().getDomElementDataAttribute("elementIdentifier"))}export function getAbstractViewFormElementDomElement(e){let t;return t="string"==typeof e?e:getUtility().isUndefinedOrNull(e)?getCurrentlySelectedFormElement().get("__identifierPath"):e.get("__identifierPath"),$(getHelper().getDomElementDataAttribute("elementIdentifier","bracesWithKeyValue",[t]),stageDomElement)}export function removeAllStageToolbars(){$(getHelper().getDomElementDataIdentifierSelector("abstractViewToolbar"),stageDomElement).off().empty().remove()}export function createAbstractViewFormElementToolbar(e){let t;assert("object"===$.type(e),'Invalid parameter "formElement"',1479035778);const n=getFormElementDefinition(e,void 0);return n._isTopLevelFormElement?$():(t=getHelper().getTemplate("FormElement-_ElementToolbar").clone(),t.length?(t=$($(t.html())),getHelper().getTemplatePropertyDomElement("_type",t).text(getFormElementDefinition(e,"label")),getHelper().getTemplatePropertyDomElement("_identifier",t).text(e.get("identifier")),n._isCompositeFormElement?(getViewModel().hideComponent($(getHelper().getDomElementDataIdentifierSelector("abstractViewToolbarNewElement"),t)),$(getHelper().getDomElementDataIdentifierSelector("abstractViewToolbarNewElementSplitButtonAfter"),t).on("click",(function(){getPublisherSubscriber().publish("view/stage/abstract/elementToolbar/button/newElement/clicked",["view/insertElements/perform/after",{disableElementTypes:[],onlyEnableElementTypes:[]}])})),$(getHelper().getDomElementDataIdentifierSelector("abstractViewToolbarNewElementSplitButtonInside"),t).on("click",(function(){getPublisherSubscriber().publish("view/stage/abstract/elementToolbar/button/newElement/clicked",["view/insertElements/perform/inside",{disableElementTypes:[],onlyEnableElementTypes:[]}])}))):(getViewModel().hideComponent($(getHelper().getDomElementDataIdentifierSelector("abstractViewToolbarNewElementSplitButton"),t)),$(getHelper().getDomElementDataIdentifierSelector("abstractViewToolbarNewElement"),t).on("click",(function(){getPublisherSubscriber().publish("view/stage/abstract/elementToolbar/button/newElement/clicked",["view/insertElements/perform/after",{disableElementTypes:[]}])}))),$(getHelper().getDomElementDataIdentifierSelector("abstractViewToolbarRemoveElement"),t).on("click",(function(){getViewModel().showRemoveFormElementModal()})),t):$())}export function createAndAddAbstractViewFormElementToolbar(e,t,n){getUtility().isUndefinedOrNull(t)&&(t=getCurrentlySelectedFormElement()),n?createAbstractViewFormElementToolbar(t).fadeOut(0,(function(){e.prepend($(this)),$(getHelper().getDomElementDataIdentifierSelector("abstractViewToolbar"),e).fadeIn("fast")})):e.prepend(createAbstractViewFormElementToolbar(t))}export function renderAbstractStageArea(e,t){getUtility().isUndefinedOrNull(e)&&(e=getFormEditorApp().getCurrentlySelectedPageIndex()),stageDomElement.off().empty().append(renderFormDefinitionPageAsSortableList(e)),stageDomElement.on("click",(function(e){const t=$(e.target).closest(getHelper().getDomElementDataAttribute("elementIdentifier","bracesWithKey")).attr(getHelper().getDomElementDataAttribute("elementIdentifier"));!getUtility().isUndefinedOrNull(t)&&getUtility().isNonEmptyString(t)&&getPublisherSubscriber().publish("view/stage/element/clicked",[t])})),configuration.isSortable&&addSortableEvents(),"function"===$.type(t)&&t()}export function renderPreviewStageArea(e){assert(getUtility().isNonEmptyString(e),'Invalid parameter "html"',1475424409),stageDomElement.off().empty().html(e),$(":input",stageDomElement).prop("disabled","disabled").on("click dblclick select focus keydown keypress keyup mousedown mouseup",(function(e){return e.preventDefault()})),$("form",stageDomElement).submit((function(e){return e.preventDefault()})),getAllFormElementDomElements().each((function(){const e=getFormEditorApp().getFormElementByIdentifierPath($(this).data("elementIdentifierPath"));getFormElementDefinition(e,"_isTopLevelFormElement")||$(this).attr("title","identifier: "+e.get("identifier")+" (type: "+e.get("type")+")"),getFormElementDefinition(e,"_isTopLevelFormElement")&&$(this).addClass(getHelper().getDomElementClassName("formElementIsTopLevel")),getFormElementDefinition(e,"_isCompositeFormElement")&&$(this).addClass(getHelper().getDomElementClassName("formElementIsComposit"))}))}export function eachTemplateProperty(e,t,n){$(getHelper().getDomElementDataAttribute("templateProperty","bracesWithKey"),t).each((function(t,r){const o=$(r).attr(getHelper().getDomElementDataAttribute("templateProperty")),l=e.get(o);"function"===$.type(n)&&n(o,l,r)}))}export function renderCheckboxTemplate(e,t){renderSimpleTemplateWithValidators(e,t),eachTemplateProperty(e,t,(function(e,t,n){("boolean"===$.type(t)&&t||"true"===t||1===t||"1"===t)&&$(n).addClass(getHelper().getDomElementClassName("noNesting"))}))}export function renderSimpleTemplate(e,t){assert("object"===$.type(e),'Invalid parameter "formElement"',1479035696),eachTemplateProperty(e,t,((e,t,n)=>{setTemplateTextContent(n,t)})),Icons.getIcon(getFormElementDefinition(e,"iconIdentifier"),Icons.sizes.small,null,Icons.states.default,Icons.markupIdentifiers.inline).then((function(e){$(getHelper().getDomElementDataIdentifierSelector("formElementIcon"),t).append($(e).addClass(getHelper().getDomElementClassName("icon")))})),getHelper().getTemplatePropertyDomElement("_type",t).append(document.createTextNode(getFormElementDefinition(e,"label"))),getHelper().getTemplatePropertyDomElement("_identifier",t).append(document.createTextNode(e.get("identifier")))}export function renderSimpleTemplateWithValidators(e,t){assert("object"===$.type(e),'Invalid parameter "formElement"',1479035674),renderSimpleTemplate(e,t);const n=$(getHelper().getDomElementDataIdentifierSelector("validatorsContainer"),$(t)).clone();$(getHelper().getDomElementDataIdentifierSelector("validatorsContainer"),$(t)).empty();const r=e.get("validators");if("array"===$.type(r)){let e=0;if(r.length>0){for(let o=0,l=r.length;o<l;++o){if("NotEmpty"===r[o].identifier){getHelper().getTemplatePropertyDomElement("_required",t).text("*");continue}e++;const l=getFormEditorApp().getFormEditorDefinition("validators",r[o].identifier),i=$($(n).clone());getHelper().getTemplatePropertyDomElement("_label",i).append(document.createTextNode(l.label)),$(getHelper().getDomElementDataIdentifierSelector("validatorsContainer"),$(t)).append(i.html())}e>0&&Icons.getIcon(getHelper().getDomElementDataAttributeValue("iconValidator"),Icons.sizes.small,null,Icons.states.default,Icons.markupIdentifiers.inline).then((function(e){$(getHelper().getDomElementDataIdentifierSelector("validatorIcon"),$(t)).append($(e).addClass(getHelper().getDomElementClassName("icon")))}))}}}export function renderSelectTemplates(e,t){const n=$(getHelper().getDomElementDataIdentifierSelector("multiValueContainer"),$(t)).clone();$(getHelper().getDomElementDataIdentifierSelector("multiValueContainer"),$(t)).empty(),renderSimpleTemplateWithValidators(e,t);const r=$(getHelper().getDomElementDataIdentifierSelector("multiValueContainer"),$(t)).attr(getHelper().getDomElementDataAttribute("templateProperty")),o=e.get(r),l=(e,r,o)=>{let l=!1;const i=$($(n).clone());for(const e of Object.keys(o))if(o[e]===r){l=!0;break}getHelper().getTemplatePropertyDomElement("_label",i).append(document.createTextNode(e)),l&&getHelper().getTemplatePropertyDomElement("_label",i).addClass(getHelper().getDomElementClassName("selected")),$(getHelper().getDomElementDataIdentifierSelector("multiValueContainer"),$(t)).append(i.html())};let i=e.get("defaultValue");if(getFormEditorApp().getUtility().isUndefinedOrNull(i)?i={}:"string"===$.type(i)&&(i={0:i}),"object"===$.type(o))for(const e of Object.keys(o))l(o[e],e,i);else if("array"===$.type(o))for(const e of Object.keys(o))getUtility().isUndefinedOrNull(o[e]._label)?l(o[e],e,i):l(o[e]._label,o[e]._value,i)}export function renderFileUploadTemplates(e,t){const n=$(getHelper().getDomElementDataIdentifierSelector("multiValueContainer"),$(t)).clone();$(getHelper().getDomElementDataIdentifierSelector("multiValueContainer"),$(t)).empty(),renderSimpleTemplateWithValidators(e,t);const r=$(getHelper().getDomElementDataIdentifierSelector("multiValueContainer"),$(t)).attr(getHelper().getDomElementDataAttribute("templateProperty")),o=e.get(r),l=function(e){const r=$($(n).clone());getHelper().getTemplatePropertyDomElement("_value",r).append(e),$(getHelper().getDomElementDataIdentifierSelector("multiValueContainer"),$(t)).append(r.html())};if("object"===$.type(o))for(const e of Object.keys(o))l(o[e]);else if("array"===$.type(o))for(let e=0,t=o.length;e<t;++e)l(o[e])}export function bootstrap(e,t,n){return formEditorApp=e,assert("object"===$.type(t),'Invalid parameter "appendToDomElement"',1478992119),stageDomElement=$(t),configuration=$.extend(!0,defaultConfiguration,n||{}),Helper.bootstrap(formEditorApp),this} \ No newline at end of file