[BUGFIX] NewContentElementWizardController to NewContentElementController 79/55479/6
authorOliver Hader <oliver@typo3.org>
Sun, 28 Jan 2018 22:38:22 +0000 (23:38 +0100)
committerOliver Hader <oliver.hader@typo3.org>
Mon, 29 Jan 2018 20:50:26 +0000 (21:50 +0100)
NewContentElementWizardController, which has been introduced for TYPO3 v9
to render the new content element process in a dedicated modal was just a
duplicate of the existing NewContentElementController class with some
minor adjustments and code flow enhancements (names, empty checks).

However, there have been several side effects like:
* hook implementing NewContentElementWizardHookInterface would have been
  called by both object instances, having different public properties -
  the most common access to $parentObject->id or ~->sys_language would
  have failed to to property visibility and change names
* the JavaScript closure callback to adjust the URL when interacting in
  the browser was hard-coded to modal rendering, with still having the
  possibility to render the old behavior e.g. in the web>list view

To overcome these flaws both mentioned classes have been merged since the
functionality was not that much different anyway. Besides that different
JavaScript client scopes ('window' or 'list_frame') are forwarded to the
according object instances.

Resolves: #83705
Releases: master
Change-Id: I472a7ec8a5d06c05e6c7053bf98b5cfacb69f9d9
Reviewed-on: https://review.typo3.org/55479
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Nicole Cordes <typo3@cordes.co>
Tested-by: Nicole Cordes <typo3@cordes.co>
Reviewed-by: Susanne Moog <susanne.moog@typo3.org>
Tested-by: Susanne Moog <susanne.moog@typo3.org>
typo3/sysext/backend/Classes/Controller/ContentElement/NewContentElementController.php
typo3/sysext/backend/Classes/Controller/Wizard/NewContentElementWizardController.php [deleted file]
typo3/sysext/backend/Classes/Tree/View/ContentCreationPagePositionMap.php
typo3/sysext/backend/Classes/Tree/View/PagePositionMap.php
typo3/sysext/backend/Configuration/Backend/Routes.php

index c66255b..52af9c1 100644 (file)
@@ -18,6 +18,7 @@ use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Backend\Template\DocumentTemplate;
 use TYPO3\CMS\Backend\Template\ModuleTemplate;
+use TYPO3\CMS\Backend\Tree\View\ContentCreationPagePositionMap;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Backend\View\BackendLayoutView;
 use TYPO3\CMS\Backend\Wizard\NewContentElementWizardHookInterface;
@@ -188,24 +189,58 @@ class NewContentElementController
      */
     public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
     {
-        $this->main();
+        $this->prepareContent('window');
         $this->moduleTemplate->setContent($this->content);
         $response->getBody()->write($this->moduleTemplate->renderContent());
         return $response;
     }
 
     /**
+     * Injects the request object for the current request or subrequest
+     * As this controller goes only through the main() method, it is rather simple for now
+     *
+     * @param ServerRequestInterface $request the current request
+     * @param ResponseInterface $response
+     * @return ResponseInterface the response with the content
+     */
+    public function wizardAction(ServerRequestInterface $request, ResponseInterface $response)
+    {
+        $this->prepareContent('list_frame');
+        $response->getBody()->write($this->content);
+        return $response;
+    }
+
+    /**
      * Creating the module output.
      *
      * @throws \UnexpectedValueException
+     * @deprecated since TYPO3 v10 (not used since v9) without substitute
      */
     public function main()
     {
+        $this->prepareContent('window');
+    }
+
+    /**
+     * Creating the module output.
+     *
+     * @param string $clientContext JavaScript client context to be used
+     *        + 'window', legacy if rendered in current document
+     *        + 'list_frame', in case rendered in global modal
+     *
+     * @throws \UnexpectedValueException
+     */
+    protected function prepareContent(string $clientContext)
+    {
         $hasAccess = true;
         if ($this->id && $this->access) {
 
             // Init position map object:
-            $posMap = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\View\ContentCreationPagePositionMap::class);
+            $posMap = GeneralUtility::makeInstance(
+                ContentCreationPagePositionMap::class,
+                null,
+                $clientContext
+            );
             $posMap->cur_sys_language = $this->sys_language;
             // If a column is pre-set:
             if (isset($this->colPos)) {
@@ -242,14 +277,6 @@ class NewContentElementController
                 }
                 $hookObject->manipulateWizardItems($wizardItems, $this);
             }
-            // Add document inline javascript
-            $this->moduleTemplate->addJavaScriptCode(
-                'NewContentElementWizardInlineJavascript',
-                '
-                               function goToalt_doc() {
-                                       ' . $this->onClickEvent . '
-                               }'
-            );
 
             // Traverse items for the wizard.
             // An item is either a header or an item rendered with a radio button and title/description and icon:
@@ -262,18 +289,18 @@ class NewContentElementController
                 $wizardOnClick = '';
                 if ($wInfo['header']) {
                     $menuItems[] = [
-                        'label' => $wInfo['header'],
+                        'label' => $wInfo['header'] ?: '-',
                         'content' => ''
                     ];
                     $key = count($menuItems) - 1;
                 } else {
                     if (!$this->onClickEvent) {
                         // Radio button:
-                        $wizardOnClick = 'document.editForm.defValues.value=unescape(' . GeneralUtility::quoteJSvalue(rawurlencode($wInfo['params'])) . ');goToalt_doc();' . (!$this->onClickEvent ? 'window.location.hash=\'#sel2\';' : '');
+                        $wizardOnClick = 'document.editForm.defValues.value=unescape(' . GeneralUtility::quoteJSvalue(rawurlencode($wInfo['params'])) . '); window.location.hash=\'#sel2\';';
                         // Onclick action for icon/title:
                         $aOnClick = 'document.getElementsByName(\'tempB\')[' . $cc . '].checked=1;' . $wizardOnClick . 'return false;';
                     } else {
-                        $aOnClick = "document.editForm.defValues.value=unescape('" . rawurlencode($wInfo['params']) . "');goToalt_doc();" . (!$this->onClickEvent ? "window.location.hash='#sel2';" : '');
+                        $aOnClick = "document.editForm.defValues.value=unescape('" . rawurlencode($wInfo['params']) . "');goToalt_doc();";
                     }
 
                     $icon = $this->moduleTemplate->getIconFactory()->getIcon($wInfo['iconIdentifier'])->render();
@@ -358,7 +385,7 @@ class NewContentElementController
     {
         $wizardItems = [];
         if (is_array($this->config)) {
-            $wizards = $this->config['wizardItems.'];
+            $wizards = $this->config['wizardItems.'] ?? [];
             $appendWizards = $this->wizard_appendWizards($wizards['elements.']);
             if (is_array($wizards)) {
                 foreach ($wizards as $groupKey => $wizardGroup) {
@@ -411,9 +438,13 @@ class NewContentElementController
         }
         if (is_array($GLOBALS['TBE_MODULES_EXT']['xMOD_db_new_content_el']['addElClasses'])) {
             foreach ($GLOBALS['TBE_MODULES_EXT']['xMOD_db_new_content_el']['addElClasses'] as $class => $path) {
-                require_once $path;
+                if (!class_exists($class) && file_exists($path)) {
+                    require_once $path;
+                }
                 $modObj = GeneralUtility::makeInstance($class);
-                $wizardElements = $modObj->proc($wizardElements);
+                if (method_exists($modObj, 'proc')) {
+                    $wizardElements = $modObj->proc($wizardElements);
+                }
             }
         }
         $returnElements = [];
diff --git a/typo3/sysext/backend/Classes/Controller/Wizard/NewContentElementWizardController.php b/typo3/sysext/backend/Classes/Controller/Wizard/NewContentElementWizardController.php
deleted file mode 100644 (file)
index 5640b55..0000000
+++ /dev/null
@@ -1,596 +0,0 @@
-<?php
-declare(strict_types = 1);
-
-namespace TYPO3\CMS\Backend\Controller\Wizard;
-
-/*
- * 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!
- */
-
-use Psr\Http\Message\ResponseInterface;
-use Psr\Http\Message\ServerRequestInterface;
-use TYPO3\CMS\Backend\Template\ModuleTemplate;
-use TYPO3\CMS\Backend\Tree\View\ContentCreationPagePositionMap;
-use TYPO3\CMS\Backend\Utility\BackendUtility;
-use TYPO3\CMS\Backend\View\BackendLayoutView;
-use TYPO3\CMS\Backend\Wizard\NewContentElementWizardHookInterface;
-use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
-use TYPO3\CMS\Core\Imaging\Icon;
-use TYPO3\CMS\Core\Localization\LanguageService;
-use TYPO3\CMS\Core\Service\DependencyOrderingService;
-use TYPO3\CMS\Core\Type\Bitmask\Permission;
-use TYPO3\CMS\Core\Utility\ArrayUtility;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Fluid\View\StandaloneView;
-
-/**
- * Script Class for the New Content element wizard
- */
-class NewContentElementWizardController
-{
-    /**
-     * ModuleTemplate object
-     *
-     * @var ModuleTemplate
-     */
-    protected $moduleTemplate;
-
-    /**
-     * Page id
-     *
-     * @var int
-     */
-    protected $id;
-
-    /**
-     * Sys language
-     *
-     * @var int
-     */
-    protected $sysLanguage = 0;
-
-    /**
-     * Return URL.
-     *
-     * @var string
-     */
-    protected $returnUrl = '';
-
-    /**
-     * If set, the content is destined for a specific column.
-     *
-     * @var int|null
-     */
-    protected $colPos;
-
-    /**
-     * @var int
-     */
-    protected $uidPid;
-
-    /**
-     * Module TSconfig.
-     *
-     * @var array
-     */
-    protected $modTsConfig = [];
-
-    /**
-     * Used to accumulate the content of the module.
-     *
-     * @var string
-     */
-    protected $content;
-
-    /**
-     * Access boolean.
-     *
-     * @var bool
-     */
-    protected $access;
-
-    /**
-     * config of the wizard
-     *
-     * @var array
-     */
-    protected $config;
-
-    /**
-     * @var array
-     */
-    protected $pageInfo;
-
-    /**
-     * @var string
-     */
-    protected $onClickEvent;
-
-    /**
-     * @var array
-     */
-    protected $moduleConfiguration;
-
-    /**
-     * @var StandaloneView
-     */
-    protected $view;
-
-    /**
-     * @var StandaloneView
-     */
-    protected $menuItemView;
-
-    /**
-     * PSR Request Object
-     *
-     * @var ServerRequestInterface
-     */
-    protected $request;
-
-    /**
-     * Constructor
-     */
-    public function __construct()
-    {
-        $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
-        $GLOBALS['SOBE'] = $this;
-        $this->view = $this->getFluidTemplateObject();
-        $this->menuItemView = $this->getFluidTemplateObject('MenuItem.html');
-        $this->init();
-    }
-
-    /**
-     * returns a new standalone view, shorthand function
-     *
-     * @param string $filename
-     * @return StandaloneView
-     */
-    protected function getFluidTemplateObject(string $filename = 'Main.html'): StandaloneView
-    {
-        /** @var StandaloneView $view */
-        $view = GeneralUtility::makeInstance(StandaloneView::class);
-        $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Templates/NewContentElement/' . $filename));
-        $view->getRequest()->setControllerExtensionName('Backend');
-        return $view;
-    }
-
-    /**
-     * Constructor, initializing internal variables.
-     */
-    protected function init()
-    {
-        $lang = $this->getLanguageService();
-        $lang->includeLLFile('EXT:lang/Resources/Private/Language/locallang_misc.xlf');
-        $originalLocalLanguage = $GLOBALS['LOCAL_LANG'];
-        $lang->includeLLFile('EXT:backend/Resources/Private/Language/locallang_db_new_content_el.xlf');
-        ArrayUtility::mergeRecursiveWithOverrule($originalLocalLanguage, $GLOBALS['LOCAL_LANG']);
-        $GLOBALS['LOCAL_LANG'] = $originalLocalLanguage;
-
-        // Setting internal vars:
-        $this->id = (int)GeneralUtility::_GP('id');
-        $this->sysLanguage = (int)GeneralUtility::_GP('sys_language_uid');
-        $this->returnUrl = GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('returnUrl'));
-        // original variable needs to be kept as is for position map
-        $GLOBALS['SOBE']->R_URI = $this->returnUrl;
-        $this->colPos = GeneralUtility::_GP('colPos') === null ? null : (int)GeneralUtility::_GP('colPos');
-        $this->uidPid = (int)GeneralUtility::_GP('uid_pid');
-        $this->moduleConfiguration['name'] = 'xMOD_db_new_content_el';
-        $this->modTsConfig = BackendUtility::getModTSconfig($this->id, 'mod.wizards.newContentElement');
-        $configuration = BackendUtility::getPagesTSconfig($this->id);
-        $this->configuration = $configuration['mod.']['wizards.']['newContentElement.'];
-        // Getting the current page and receiving access information (used in main())
-        $permissionsClause = $this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW);
-        $this->pageInfo = BackendUtility::readPageAccess($this->id, $permissionsClause);
-        $this->access = is_array($this->pageInfo);
-    }
-
-    /**
-     * Injects the request object for the current request or subrequest
-     * As this controller goes only through the main() method, it is rather simple for now
-     *
-     * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response
-     * @return ResponseInterface the response with the content
-     */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
-    {
-        $this->main();
-        $response->getBody()->write($this->content);
-        return $response;
-    }
-
-    /**
-     * Creating the module output.
-     *
-     * @throws \UnexpectedValueException
-     */
-    protected function main()
-    {
-        $hasAccess = true;
-        if ($this->id && $this->access) {
-
-            // Init position map object:
-            $positionMap = GeneralUtility::makeInstance(ContentCreationPagePositionMap::class);
-            $positionMap->cur_sys_language = $this->sysLanguage;
-            // If a column is pre-set:
-            if (isset($this->colPos)) {
-                if ($this->uidPid < 0) {
-                    $row = [];
-                    $row['uid'] = abs($this->uidPid);
-                } else {
-                    $row = '';
-                }
-                $this->onClickEvent = $positionMap->onClickInsertRecord(
-                    $row,
-                    $this->colPos,
-                    '',
-                    $this->uidPid,
-                    $this->sysLanguage
-                );
-            } else {
-                $this->onClickEvent = '';
-            }
-            // ***************************
-            // Creating content
-            // ***************************
-            // Wizard
-            $wizardItems = $this->getWizardItems();
-            // Wrapper for wizards
-            // Hook for manipulating wizardItems, wrapper, onClickEvent etc.
-            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms']['db_new_content_el']['wizardItemsHook'] ?? [] as $className) {
-                $hookObject = GeneralUtility::makeInstance($className);
-                if (!$hookObject instanceof NewContentElementWizardHookInterface) {
-                    throw new \UnexpectedValueException(
-                        $className . ' must implement interface ' . NewContentElementWizardHookInterface::class,
-                        1496496724
-                    );
-                }
-                $hookObject->manipulateWizardItems($wizardItems, $this);
-            }
-
-            // Traverse items for the wizard.
-            // An item is either a header or an item rendered with a radio button and title/description and icon:
-            $counter = ($key = 0);
-            $menuItems = [];
-
-            $this->view->assign('onClickEvent', $this->onClickEvent);
-
-            foreach ($wizardItems as $wizardKey => $wizardInformation) {
-                $wizardOnClick = '';
-                if (isset($wizardInformation['header'])) {
-                    $menuItems[] = [
-                        'label' => $wizardInformation['header'] ?: '-',
-                        'content' => ''
-                    ];
-                    $key = count($menuItems) - 1;
-                } else {
-                    if (!$this->onClickEvent) {
-                        // Radio button:
-                        $wizardOnClick = 'document.editForm.defValues.value=unescape(' . GeneralUtility::quoteJSvalue(rawurlencode($wizardInformation['params'])) . '); window.location.hash=\'#sel2\';';
-                        // Onclick action for icon/title:
-                        $actionOnClick = 'document.getElementsByName(\'tempB\')[' . $counter . '].checked=1;' . $wizardOnClick . 'return false;';
-                    } else {
-                        $actionOnClick = 'document.editForm.defValues.value=unescape("' . rawurlencode($wizardInformation['params']) . '");goToalt_doc();' . (!$this->onClickEvent ? 'window.location.hash=\'#sel2\';' : '');
-                    }
-
-                    $icon = $this->moduleTemplate->getIconFactory()->getIcon($wizardInformation['iconIdentifier'])->render();
-
-                    $this->menuItemView->assignMultiple(
-                        [
-                            'onClickEvent' => $this->onClickEvent,
-                            'aOnClick' => $actionOnClick,
-                            'wizardInformation' => $wizardInformation,
-                            'icon' => $icon,
-                            'wizardOnClick' => $wizardOnClick,
-                            'wizardKey' => $wizardKey
-                        ]
-                    );
-                    $menuItems[$key]['content'] .= $this->menuItemView->render();
-                    $counter++;
-                }
-            }
-
-            $this->view->assign('renderedTabs', $this->moduleTemplate->getDynamicTabMenu(
-                $menuItems,
-                'new-content-element-wizard'
-            ));
-
-            // If the user must also select a column:
-            if (!$this->onClickEvent) {
-
-                // Load SHARED page-TSconfig settings and retrieve column list from there, if applicable:
-                $colPosArray = GeneralUtility::callUserFunction(
-                    BackendLayoutView::class . '->getColPosListItemsParsed',
-                    $this->id,
-                    $this
-                );
-                $colPosIds = array_column($colPosArray, 1);
-                // Removing duplicates, if any
-                $colPosList = implode(',', array_unique(array_map('intval', $colPosIds)));
-                // Finally, add the content of the column selector to the content:
-                $this->view->assign(
-                    'posMap',
-                    $positionMap->printContentElementColumns($this->id, 0, $colPosList, 1, $this->returnUrl)
-                );
-            }
-        } else {
-            // In case of no access:
-            $hasAccess = false;
-        }
-        $this->view->assign('hasAccess', $hasAccess);
-
-        $this->content = $this->view->render();
-        // Setting up the buttons and markers for docheader
-        $this->getButtons();
-    }
-
-    /**
-     * Returns the array of elements in the wizard display.
-     * For the plugin section there is support for adding elements there from a global variable.
-     *
-     * @return array
-     */
-    protected function getWizardItems(): array
-    {
-        $wizardItems = [];
-        if (isset($this->configuration['wizardItems.'])) {
-            $wizards = $this->configuration['wizardItems.'];
-            if (empty($wizards['elements.'])) {
-                $wizards['elements.'] = [];
-            }
-            $appendWizards = $this->appendWizards($wizards['elements.']);
-            if (is_array($wizards)) {
-                foreach ($wizards as $groupKey => $wizardGroup) {
-                    if (is_array($wizards[$groupKey])) {
-                        $this->prepareDependencyOrdering($wizards[$groupKey], 'before');
-                        $this->prepareDependencyOrdering($wizards[$groupKey], 'after');
-                    }
-                }
-                $wizards = GeneralUtility::makeInstance(DependencyOrderingService::class)->orderByDependencies($wizards);
-
-                foreach ($wizards as $groupKey => $wizardGroup) {
-                    if (is_array($wizardGroup)) {
-                        $groupKey = rtrim($groupKey, '.');
-                        $showItems = GeneralUtility::trimExplode(',', $wizardGroup['show'], true);
-                        $showAll = in_array('*', $showItems, true);
-                        $groupItems = [];
-                        if (is_array($appendWizards[$groupKey . '.']['elements.'])) {
-                            $wizardElements = array_merge(
-                                (array)$wizardGroup['elements.'],
-                                $appendWizards[$groupKey . '.']['elements.']
-                            );
-                        } else {
-                            $wizardElements = $wizardGroup['elements.'];
-                        }
-                        if (is_array($wizardElements)) {
-                            foreach ($wizardElements as $itemKey => $itemConfiguration) {
-                                $itemKey = rtrim($itemKey, '.');
-                                if (($showAll || in_array($itemKey, $showItems) && is_array($itemConfiguration))) {
-                                    $item = $this->getItem($itemConfiguration);
-                                    if ($item) {
-                                        $groupItems[$groupKey . '_' . $itemKey] = $item;
-                                    }
-                                }
-                            }
-                        }
-                        if (!empty($groupItems)) {
-                            $wizardItems[$groupKey] = $this->getGroupHeader($wizardGroup);
-                            $wizardItems = array_merge($wizardItems, $groupItems);
-                        }
-                    }
-                }
-            }
-        }
-        // Remove elements where preset values are not allowed:
-        $this->removeInvalidElements($wizardItems);
-        return $wizardItems;
-    }
-
-    /**
-     * @param array $wizardElements
-     * @return array $returnElements
-     */
-    protected function appendWizards(array $wizardElements): array
-    {
-        if (is_array($GLOBALS['TBE_MODULES_EXT']['xMOD_db_new_content_el']['addElClasses'])) {
-            foreach ($GLOBALS['TBE_MODULES_EXT']['xMOD_db_new_content_el']['addElClasses'] as $class => $path) {
-                if (!class_exists($class) && file_exists($path)) {
-                    require_once $path;
-                }
-                $moduleObject = GeneralUtility::makeInstance($class);
-                if (method_exists($moduleObject, 'proc')) {
-                    $wizardElements = $moduleObject->proc($wizardElements);
-                }
-            }
-        }
-        $returnElements = [];
-        foreach ($wizardElements as $key => $wizardItem) {
-            preg_match('/^[a-zA-Z0-9]+_/', $key, $group);
-            $wizardGroup = $group[0] ? substr($group[0], 0, -1) . '.' : $key;
-            $returnElements[$wizardGroup]['elements.'][substr($key, strlen($wizardGroup)) . '.'] = $wizardItem;
-        }
-        return $returnElements;
-    }
-
-    /**
-     * Prepare a wizard tab configuration for sorting.
-     *
-     * @param array $wizardGroup TypoScript wizard tab configuration
-     * @param string $key Which array key should be prepared
-     */
-    protected function prepareDependencyOrdering(array &$wizardGroup, string $key)
-    {
-        if (isset($wizardGroup[$key])) {
-            $wizardGroup[$key] = GeneralUtility::trimExplode(',', $wizardGroup[$key]);
-            $wizardGroup[$key] = array_map(function ($s) {
-                return $s . '.';
-            }, $wizardGroup[$key]);
-        }
-    }
-
-    /**
-     * @param array $itemConfiguration
-     * @return array $itemConfiguration
-     */
-    protected function getItem(array $itemConfiguration): array
-    {
-        $itemConfiguration['title'] = $this->getLanguageService()->sL($itemConfiguration['title']);
-        $itemConfiguration['description'] = $this->getLanguageService()->sL($itemConfiguration['description']);
-        $itemConfiguration['tt_content_defValues'] = $itemConfiguration['tt_content_defValues.'];
-        unset($itemConfiguration['tt_content_defValues.']);
-        return $itemConfiguration;
-    }
-
-    /**
-     * @param array $wizardGroup
-     * @return array
-     */
-    protected function getGroupHeader(array $wizardGroup): array
-    {
-        return [
-            'header' => $this->getLanguageService()->sL($wizardGroup['header'])
-        ];
-    }
-
-    /**
-     * Checks the array for elements which might contain unallowed default values and will unset them!
-     * Looks for the "tt_content_defValues" key in each element and if found it will traverse that array as fieldname /
-     * value pairs and check.
-     * The values will be added to the "params" key of the array (which should probably be unset or empty by default).
-     *
-     * @param array $wizardItems Wizard items, passed by reference
-     */
-    protected function removeInvalidElements(&$wizardItems)
-    {
-        // Get TCEFORM from TSconfig of current page
-        $row = ['pid' => $this->id];
-        $tceFormTsConfig = BackendUtility::getTCEFORM_TSconfig('tt_content', $row);
-        $headersUsed = [];
-        // Traverse wizard items:
-        foreach ($wizardItems as $key => $configuration) {
-            // Exploding parameter string, if any (old style)
-            if ($wizardItems[$key]['params']) {
-                // Explode GET vars recursively
-                $temporaryGetVariables = GeneralUtility::explodeUrl2Array($wizardItems[$key]['params'], true);
-                // If tt_content values are set, merge them into the tt_content_defValues array,
-                // unset them from $temporaryGetVariables and re-implode $temporaryGetVariables into the param string
-                // (in case remaining parameters are around).
-                if (is_array($temporaryGetVariables['defVals']['tt_content'])) {
-                    $wizardItems[$key]['tt_content_defValues'] = array_merge(
-                        is_array($wizardItems[$key]['tt_content_defValues']) ? $wizardItems[$key]['tt_content_defValues'] : [],
-                        $temporaryGetVariables['defVals']['tt_content']
-                    );
-                    unset($temporaryGetVariables['defVals']['tt_content']);
-                    $wizardItems[$key]['params'] = GeneralUtility::implodeArrayForUrl('', $temporaryGetVariables);
-                }
-            }
-            // If tt_content_defValues are defined...:
-            if (is_array($wizardItems[$key]['tt_content_defValues'])) {
-                $backendUser = $this->getBackendUser();
-                // Traverse field values:
-                foreach ($wizardItems[$key]['tt_content_defValues'] as $fieldName => $fieldValue) {
-                    if (is_array($GLOBALS['TCA']['tt_content']['columns'][$fieldName])) {
-                        // Get information about if the field value is OK:
-                        $configuration = &$GLOBALS['TCA']['tt_content']['columns'][$fieldName]['config'];
-                        $authenticationModeDeny = $configuration['type'] === 'select' && $configuration['authMode']
-                            && !$backendUser->checkAuthMode(
-                                'tt_content',
-                                $fieldName,
-                                $fieldValue,
-                                $configuration['authMode']
-                            );
-                        // explode TSconfig keys only as needed
-                        if (!isset($removeItems[$fieldName])) {
-                            $removeItems[$fieldName] = GeneralUtility::trimExplode(
-                                ',',
-                                $tceFormTsConfig[$fieldName]['removeItems'],
-                                true
-                            );
-                        }
-                        if (!isset($keepItems[$fieldName])) {
-                            $keepItems[$fieldName] = GeneralUtility::trimExplode(
-                                ',',
-                                $tceFormTsConfig[$fieldName]['keepItems'],
-                                true
-                            );
-                        }
-                        $isNotInKeepItems = !empty($keepItems[$fieldName]) && !in_array(
-                            $fieldValue,
-                                $keepItems[$fieldName]
-                        );
-                        if ($authenticationModeDeny || $fieldName === 'CType' && (in_array(
-                            $fieldValue,
-                                    $removeItems[$fieldName]
-                        ) || $isNotInKeepItems)
-                        ) {
-                            // Remove element all together:
-                            unset($wizardItems[$key]);
-                            break;
-                        }
-                        // Add the parameter:
-                        $wizardItems[$key]['params'] .= '&defVals[tt_content][' . $fieldName . ']=' . rawurlencode($this->getLanguageService()->sL($fieldValue));
-                        $headerKey = explode('_', $key);
-                        $headersUsed[$headerKey[0]] = $headerKey[0];
-                    }
-                }
-            }
-        }
-        // remove headers without elements
-        foreach ($wizardItems as $key => $configuration) {
-            $headerKey = explode('_', $key);
-            if ($headerKey[0] && !$headerKey[1] && !in_array($headerKey[0], $headersUsed)) {
-                unset($wizardItems[$key]);
-            }
-        }
-    }
-
-    /**
-     * Create the panel of buttons for submitting the form or otherwise perform operations.
-     */
-    protected function getButtons()
-    {
-        $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
-        if ($this->returnUrl) {
-            $backButton = $buttonBar->makeLinkButton()
-                ->setHref($this->returnUrl)
-                ->setTitle($this->getLanguageService()->getLL('goBack'))
-                ->setIcon($this->moduleTemplate->getIconFactory()->getIcon(
-                    'actions-view-go-back',
-                    Icon::SIZE_SMALL
-                ));
-            $buttonBar->addButton($backButton);
-        }
-        $contextSensitiveHelpButton = $buttonBar->makeHelpButton()->setModuleName('xMOD_csh_corebe')->setFieldName('new_ce');
-        $buttonBar->addButton($contextSensitiveHelpButton);
-    }
-
-    /**
-     * Returns LanguageService
-     *
-     * @return LanguageService
-     */
-    protected function getLanguageService(): LanguageService
-    {
-        return $GLOBALS['LANG'];
-    }
-
-    /**
-     * Returns the current BE user.
-     *
-     * @return BackendUserAuthentication
-     */
-    protected function getBackendUser(): BackendUserAuthentication
-    {
-        return $GLOBALS['BE_USER'];
-    }
-}
index 7d344ed..3bbde87 100644 (file)
@@ -58,6 +58,6 @@ class ContentCreationPagePositionMap extends PagePositionMap
             'defVals[tt_content][sys_language_uid]' => $sys_lang,
             'returnUrl' => $GLOBALS['SOBE']->R_URI
         ]);
-        return 'list_frame.location.href=' . GeneralUtility::quoteJSvalue($location) . '+document.editForm.defValues.value; return false;';
+        return $this->clientContext . '.location.href=' . GeneralUtility::quoteJSvalue($location) . '+document.editForm.defValues.value; return false;';
     }
 }
index 67f672d..7866d87 100644 (file)
@@ -115,15 +115,22 @@ class PagePositionMap
     protected $iconFactory;
 
     /**
+     * @var string
+     */
+    protected $clientContext;
+
+    /**
      * Constructor allowing to set pageTreeImplementation
      *
      * @param string $pageTreeClassName
+     * @param string $clientContext JavaScript context of view client (either 'window' or 'list_frame')
      */
-    public function __construct($pageTreeClassName = null)
+    public function __construct(string $pageTreeClassName = null, string $clientContext = 'window')
     {
         if ($pageTreeClassName !== null) {
             $this->pageTreeClassName = $pageTreeClassName;
         }
+        $this->clientContext = $clientContext;
         $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
     }
 
@@ -284,7 +291,7 @@ class PagePositionMap
                     'returnUrl'   => GeneralUtility::getIndpEnv('REQUEST_URI')
                 ]
             );
-            return 'list_frame.location.href=' . GeneralUtility::quoteJSvalue((string)$url) . ';';
+            return $this->clientContext . '.location.href=' . GeneralUtility::quoteJSvalue((string)$url) . ';';
         }
         $params = '&edit[pages][' . $pid . ']=new&returnNewPageId=1';
         return BackendUtility::editOnClick($params, '', $this->R_URI);
@@ -577,7 +584,7 @@ class PagePositionMap
             ]);
         }
         // returns to prev. page
-        return 'list_frame.location.href=' . GeneralUtility::quoteJSvalue((string)$location) . ';return false;';
+        return $this->clientContext . '.location.href=' . GeneralUtility::quoteJSvalue((string)$location) . ';return false;';
     }
 
     /**
index 5dfef0e..15ba8be 100644 (file)
@@ -137,16 +137,16 @@ return [
         'target' => Controller\Page\NewMultiplePagesController::class . '::mainAction'
     ],
 
-    // Register new content element module
+    // Register new content element module (as whole document)
     'new_content_element' => [
         'path' => '/record/content/new',
         'target' => Controller\ContentElement\NewContentElementController::class . '::mainAction'
     ],
 
-    // Register new content element module
+    // Register new content element module (in modal)
     'new_content_element_wizard' => [
         'path' => '/record/content/wizard/new',
-        'target' => Controller\Wizard\NewContentElementWizardController::class . '::mainAction'
+        'target' => Controller\ContentElement\NewContentElementController::class . '::wizardAction'
     ],
 
     // Register move element module