[TASK] EXT:form - make 'grid rows' independent from 'grid containers' 66/52166/5
authorRalf Zimmermann <ralf.zimmermann@tritum.de>
Sun, 26 Mar 2017 10:54:07 +0000 (12:54 +0200)
committerFrank Naegler <frank.naegler@typo3.org>
Mon, 27 Mar 2017 20:59:17 +0000 (22:59 +0200)
* Create 'grid rows' without 'grid container' wrappers
* Disable 'grid containers' within the form editor by default
  because twitter bootstrap prohibits container nesting

Resolves: #80455
Releases: master
Change-Id: I3997943858ac3b235094b765697f724cb1e4c95d
Reviewed-on: https://review.typo3.org/52166
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Susanne Moog <susanne.moog@typo3.org>
Tested-by: Susanne Moog <susanne.moog@typo3.org>
Reviewed-by: Frank Naegler <frank.naegler@typo3.org>
Tested-by: Frank Naegler <frank.naegler@typo3.org>
typo3/sysext/form/Classes/Domain/Model/FormElements/GridRow.php
typo3/sysext/form/Classes/ViewHelpers/GridColumnClassAutoConfigurationViewHelper.php
typo3/sysext/form/Configuration/Yaml/BaseSetup.yaml
typo3/sysext/form/Configuration/Yaml/FormEditorSetup.yaml
typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor.js
typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/Core.js
typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/StageComponent.js
typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/TreeComponent.js
typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/ViewModel.js

index 06f03b3..5be61bd 100644 (file)
@@ -31,24 +31,6 @@ class GridRow extends Section implements GridRowInterface
 {
 
     /**
-     * Register this element at the parent form, if there is a connection to the parent form.
-     *
-     * @return void
-     * @throws TypeDefinitionNotValidException
-     * @internal
-     */
-    public function registerInFormIfPossible()
-    {
-        if (!$this->getParentRenderable() instanceof GridContainerInterface) {
-            throw new TypeDefinitionNotValidException(
-                sprintf('Grid rows ("%s") only allowed within grid containers.', $this->getIdentifier()),
-                1489413805
-            );
-        }
-        parent::registerInFormIfPossible();
-    }
-
-    /**
      * Add a new form element at the end of the grid row
      *
      * @param FormElementInterface $formElement The form element to add
@@ -63,11 +45,6 @@ class GridRow extends Section implements GridRowInterface
                 sprintf('Grid containers ("%s") within grid rows ("%s") are not allowed.', $formElement->getIdentifier(), $this->getIdentifier()),
                 1489413379
             );
-        } elseif ($formElement instanceof GridRowInterface) {
-            throw new TypeDefinitionNotValidException(
-                sprintf('Grid rows ("%s") within grid rows ("%s") are not allowed.', $formElement->getIdentifier(), $this->getIdentifier()),
-                1489413696
-            );
         }
 
         $this->addRenderable($formElement);
@@ -91,11 +68,6 @@ class GridRow extends Section implements GridRowInterface
                 sprintf('Grid containers ("%s") within grid rows ("%s") are not allowed.', $element->getIdentifier(), $this->getIdentifier()),
                 1489413538
             );
-        } elseif ($element instanceof GridRowInterface) {
-            throw new TypeDefinitionNotValidException(
-                sprintf('Grid rows ("%s") within grid rows ("%s") are not allowed.', $element->getIdentifier(), $this->getIdentifier()),
-                1489413697
-            );
         }
 
         return $element;
index e70c5f3..93bf6e2 100644 (file)
@@ -16,6 +16,7 @@ namespace TYPO3\CMS\Form\ViewHelpers;
  */
 
 use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
+use TYPO3\CMS\Form\Domain\Model\FormElements\GridContainerInterface;
 use TYPO3\CMS\Form\Domain\Model\Renderable\RootRenderableInterface;
 use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
 use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
@@ -63,23 +64,27 @@ class GridColumnClassAutoConfigurationViewHelper extends AbstractViewHelper
         $gridContainerElement = $gridRowElement->getParentRenderable();
         $gridRowEChildElements = $gridRowElement->getElementsRecursively();
 
-        $gridContainerViewPortConfiguration = $gridContainerElement->getProperties()['gridColumnClassAutoConfiguration'];
-        if (empty($gridContainerViewPortConfiguration)) {
-            return '';
+        if ($gridContainerElement instanceof GridContainerInterface) {
+            $gridViewPortConfiguration = $gridContainerElement->getProperties()['gridColumnClassAutoConfiguration'];
+        } else {
+            $gridViewPortConfiguration = $gridRowElement->getProperties()['gridColumnClassAutoConfiguration'];
         }
 
-        $gridSize = (int)$gridContainerViewPortConfiguration['gridSize'];
+        if (empty($gridViewPortConfiguration)) {
+            return '';
+        }
+        $gridSize = (int)$gridViewPortConfiguration['gridSize'];
 
         $columnsToCalculate = [];
         $usedColumns = [];
         foreach ($gridRowEChildElements as $childElement) {
             if (empty($childElement->getProperties()['gridColumnClassAutoConfiguration'])) {
-                foreach ($gridContainerViewPortConfiguration['viewPorts'] as $viewPortName => $configuration) {
+                foreach ($gridViewPortConfiguration['viewPorts'] as $viewPortName => $configuration) {
                     $columnsToCalculate[$viewPortName]['elements']++;
                 }
             } else {
                 $gridColumnViewPortConfiguration = $childElement->getProperties()['gridColumnClassAutoConfiguration'];
-                foreach ($gridContainerViewPortConfiguration['viewPorts'] as $viewPortName => $configuration) {
+                foreach ($gridViewPortConfiguration['viewPorts'] as $viewPortName => $configuration) {
                     $configuration = $gridColumnViewPortConfiguration['viewPorts'][$viewPortName];
                     if (
                         isset($configuration['numbersOfColumnsToUse'])
@@ -100,7 +105,7 @@ class GridColumnClassAutoConfigurationViewHelper extends AbstractViewHelper
         }
 
         $classes = [];
-        foreach ($gridContainerViewPortConfiguration['viewPorts'] as $viewPortName => $configuration) {
+        foreach ($gridViewPortConfiguration['viewPorts'] as $viewPortName => $configuration) {
             if (isset($usedColumns[$viewPortName]['concreteNumbersOfColumnsToUse'])) {
                 $numbersOfColumnsToUse = $usedColumns[$viewPortName]['concreteNumbersOfColumnsToUse'];
             } else {
index a8b4fd3..a0a500b 100644 (file)
@@ -77,6 +77,7 @@ TYPO3:
                 _isGridContainerFormElement: true
               properties:
                 elementClassAttribute: 'container'
+                # overrules 'GridRow.properties.gridColumnClassAutoConfiguration'
                 gridColumnClassAutoConfiguration:
                   gridSize: 12
                   viewPorts:
@@ -95,6 +96,17 @@ TYPO3:
               implementationClassName: 'TYPO3\CMS\Form\Domain\Model\FormElements\GridRow'
               properties:
                 elementClassAttribute: 'row'
+                gridColumnClassAutoConfiguration:
+                  gridSize: 12
+                  viewPorts:
+                    xs:
+                      classPattern: 'col-xs-{@numbersOfColumnsToUse}'
+                    sm:
+                      classPattern: 'col-sm-{@numbersOfColumnsToUse}'
+                    md:
+                      classPattern: 'col-md-{@numbersOfColumnsToUse}'
+                    lg:
+                      classPattern: 'col-lg-{@numbersOfColumnsToUse}'
               renderingOptions:
                 _isCompositeFormElement: true
                 _isGridRowFormElement: true
index 8716b32..142d420 100644 (file)
@@ -304,8 +304,6 @@ TYPO3:
             GridContainer:
               formEditor:
                 label: 'formEditor.elements.GridContainer.label'
-                group: container
-                groupSorting: 200
                 _isCompositeFormElement: true
                 _isGridContainerFormElement: true
                 iconIdentifier: 't3-form-icon-gridcontainer'
index 14e42a5..9f620eb 100644 (file)
@@ -815,6 +815,18 @@ define(['jquery',
             /**
              * @public
              *
+             * @param object formElement
+             * @return object|null
+             */
+            function findEnclosingGridRowFormElement(formElement) {
+                return _getRepository().findEnclosingGridRowFormElement(
+                    _getRepository().findFormElement(formElement)
+                );
+            };
+
+            /**
+             * @public
+             *
              * @return object
              */
             function getNonCompositeNonToplevelFormElements() {
@@ -1071,6 +1083,7 @@ define(['jquery',
                 getLastTopLevelElementOnCurrentPage: getLastTopLevelElementOnCurrentPage,
                 findEnclosingCompositeFormElementWhichIsNotOnTopLevel: findEnclosingCompositeFormElementWhichIsNotOnTopLevel,
                 findEnclosingGridContainerFormElement: findEnclosingGridContainerFormElement,
+                findEnclosingGridRowFormElement: findEnclosingGridRowFormElement,
                 isRootFormElementSelected: isRootFormElementSelected,
                 getLastFormElementWithinParentFormElement: getLastFormElementWithinParentFormElement,
                 getNonCompositeNonToplevelFormElements: getNonCompositeNonToplevelFormElements,
index d1824db..9be812a 100644 (file)
@@ -1356,6 +1356,29 @@ define(['jquery'], function($) {
             /**
              * @param object formElement
              * @return object|null
+             * @throws 1490520271
+             */
+            function findEnclosingGridRowFormElement(formElement) {
+                var formElementTypeDefinition;
+                utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1490520271);
+
+                formElementTypeDefinition = repository().getFormEditorDefinition('formElements', formElement.get('type'));
+                while (!formElementTypeDefinition['_isGridRowFormElement']) {
+                    if (formElementTypeDefinition['_isTopLevelFormElement']) {
+                        return null;
+                    }
+                    formElement = formElement.get('__parentRenderable');
+                    formElementTypeDefinition = repository().getFormEditorDefinition('formElements', formElement.get('type'));
+                }
+                if (formElementTypeDefinition['_isTopLevelFormElement']) {
+                    return null;
+                }
+                return formElement;
+            };
+
+            /**
+             * @param object formElement
+             * @return object|null
              * @throws 1475364965
              */
             function findEnclosingCompositeFormElementWhichIsNotOnTopLevel(formElement) {
@@ -1706,6 +1729,7 @@ define(['jquery'], function($) {
                 findEnclosingCompositeFormElementWhichIsNotOnTopLevel: findEnclosingCompositeFormElementWhichIsNotOnTopLevel,
                 findEnclosingCompositeFormElementWhichIsOnTopLevel: findEnclosingCompositeFormElementWhichIsOnTopLevel,
                 findEnclosingGridContainerFormElement: findEnclosingGridContainerFormElement,
+                findEnclosingGridRowFormElement: findEnclosingGridRowFormElement,
                 getIndexForEnclosingCompositeFormElementWhichIsOnTopLevelForFormElement: getIndexForEnclosingCompositeFormElementWhichIsOnTopLevelForFormElement,
                 getNonCompositeNonToplevelFormElements: getNonCompositeNonToplevelFormElements,
 
index ff2a117..69f7478 100644 (file)
@@ -372,14 +372,10 @@ define(['jquery',
 
                     if (
                         formElementTypeDefinition['_isGridContainerFormElement']
-                        && getFormEditorApp().findEnclosingGridContainerFormElement(targetFormElementIdentifierPath)
-                    ) {
-                        return false;
-                    }
-
-                    if (
-                        formElementTypeDefinition['_isGridRowFormElement']
-                        && !targetFormElementTypeDefinition['_isGridContainerFormElement']
+                        && (
+                            getFormEditorApp().findEnclosingGridContainerFormElement(targetFormElementIdentifierPath)
+                            || getFormEditorApp().findEnclosingGridRowFormElement(targetFormElementIdentifierPath)
+                        )
                     ) {
                         return false;
                     }
@@ -701,10 +697,21 @@ define(['jquery',
                     disableElementTypes = [];
                     onlyEnableElementTypes = [];
                     if (formElementTypeDefinition['_isGridRowFormElement']) {
-                        onlyEnableElementTypes = ['GridRow'];
-                        disableElementTypes = [];
+                        if (getFormEditorApp().findEnclosingGridContainerFormElement(getCurrentlySelectedFormElement())) {
+                            onlyEnableElementTypes = ['GridRow'];
+                        } else if (getFormEditorApp().findEnclosingGridRowFormElement(getCurrentlySelectedFormElement().get('__parentRenderable'))) {
+                            disableElementTypes = ['GridContainer'];
+                        }
                     } else {
-                        disableElementTypes = ['GridRow'];
+                        if (
+                            !formElementTypeDefinition['_isGridContainerFormElement']
+                            && (
+                                getFormEditorApp().findEnclosingGridContainerFormElement(getCurrentlySelectedFormElement())
+                                || getFormEditorApp().findEnclosingGridRowFormElement(getCurrentlySelectedFormElement())
+                            )
+                        ) {
+                            disableElementTypes = ['GridContainer'];
+                        }
                     }
 
                     getPublisherSubscriber().publish('view/stage/abstract/elementToolbar/button/newElement/clicked', [
@@ -719,14 +726,18 @@ define(['jquery',
                 $(getHelper().getDomElementDataIdentifierSelector('abstractViewToolbarNewElementSplitButtonInside'), template).on('click', function(e) {
                     var disableElementTypes, onlyEnableElementTypes;
 
-                    disableElementTypes = ['GridRow'];
+                    disableElementTypes = [];
                     onlyEnableElementTypes = [];
                     if (formElementTypeDefinition['_isGridContainerFormElement']) {
                         onlyEnableElementTypes = ['GridRow'];
-                        disableElementTypes = [];
-                    } else if (formElementTypeDefinition['_isGridRowFormElement']) {
-                        onlyEnableElementTypes = [];
-                        disableElementTypes = ['GridContainer', 'GridRow'];
+                    } else if (
+                        formElementTypeDefinition['_isGridRowFormElement']
+                        || (
+                            getFormEditorApp().findEnclosingGridContainerFormElement(getCurrentlySelectedFormElement())
+                            || getFormEditorApp().findEnclosingGridRowFormElement(getCurrentlySelectedFormElement())
+                        )
+                    ) {
+                        disableElementTypes = ['GridContainer'];
                     }
 
                     getPublisherSubscriber().publish('view/stage/abstract/elementToolbar/button/newElement/clicked', [
@@ -742,14 +753,11 @@ define(['jquery',
                 getViewModel().hideComponent($(getHelper().getDomElementDataIdentifierSelector('abstractViewToolbarNewElementSplitButton'), template));
 
                 $(getHelper().getDomElementDataIdentifierSelector('abstractViewToolbarNewElement'), template).on('click', function(e) {
-                    var disableElementTypes, onlyEnableElementTypes;
+                    var disableElementTypes;
 
                     disableElementTypes = [];
-                    onlyEnableElementTypes = [];
-                    if (getFormEditorApp().findEnclosingGridContainerFormElement(formElement)) {
-                        disableElementTypes = ['GridContainer', 'GridRow'];
-                    } else {
-                        disableElementTypes = ['GridRow'];
+                    if (getFormEditorApp().findEnclosingGridRowFormElement(formElement)) {
+                        disableElementTypes = ['GridContainer'];
                     }
 
                     getPublisherSubscriber().publish(
index f9c0ac0..03a4512 100644 (file)
@@ -325,14 +325,10 @@ define(['jquery',
 
                     if (
                         formElementTypeDefinition['_isGridContainerFormElement']
-                        && getFormEditorApp().findEnclosingGridContainerFormElement(targetFormElementIdentifierPath)
-                    ) {
-                        return false;
-                    }
-
-                    if (
-                        formElementTypeDefinition['_isGridRowFormElement']
-                        && !targetFormElementTypeDefinition['_isGridContainerFormElement']
+                        && (
+                            getFormEditorApp().findEnclosingGridContainerFormElement(targetFormElementIdentifierPath)
+                            || getFormEditorApp().findEnclosingGridRowFormElement(targetFormElementIdentifierPath)
+                        )
                     ) {
                         return false;
                     }
index fe69991..cc4813a 100644 (file)
@@ -404,10 +404,7 @@ define(['jquery',
             $(getHelper().getDomElementDataIdentifierSelector('buttonStageNewElementBottom')).on('click', function(e) {
                 getPublisherSubscriber().publish(
                     'view/stage/abstract/button/newElement/clicked', [
-                        'view/insertElements/perform/bottom',
-                        {
-                            disableElementTypes: ['GridRow']
-                        }
+                        'view/insertElements/perform/bottom'
                     ]
                 );
             });