[TASK] Call explicit render() on icon objects
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / View / PageLayoutView.php
index b6ba61a..155e2b2 100644 (file)
@@ -16,7 +16,6 @@ namespace TYPO3\CMS\Backend\View;
 
 use TYPO3\CMS\Backend\Controller\PageLayoutController;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
-use TYPO3\CMS\Backend\Utility\IconUtility;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Database\DatabaseConnection;
 use TYPO3\CMS\Core\Imaging\Icon;
@@ -25,7 +24,10 @@ use TYPO3\CMS\Core\Messaging\FlashMessage;
 use TYPO3\CMS\Core\Page\PageRenderer;
 use TYPO3\CMS\Core\Type\Bitmask\Permission;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\StringUtility;
 use TYPO3\CMS\Core\Versioning\VersionState;
+use TYPO3\CMS\Extbase\Service\FlexFormService;
+use TYPO3\CMS\Fluid\View\StandaloneView;
 
 /**
  * Child class for the Web > Page module
@@ -173,6 +175,28 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
        public $ext_CALC_PERMS;
 
        /**
+        * Current ids page record
+        *
+        * @var array
+        */
+       protected $pageinfo;
+
+       /**
+        * Caches the available languages in a colPos
+        *
+        * @var array
+        */
+       protected $languagesInColumnCache = array();
+
+       /**
+        * Caches the amount of content elements as a matrix
+        *
+        * @var array
+        * @internal
+        */
+       protected $contentElementCache = array();
+
+       /**
         * @var IconFactory
         */
        protected $iconFactory;
@@ -334,7 +358,8 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                                rtrim(trim($this->getLanguageService()->sL(BackendUtility::getItemLabel('pages', $field))), ':')
                                        );
                                        $eI = '<a href="#" onclick="' . htmlspecialchars(BackendUtility::editOnClick($params))
-                                               . '" title="' . htmlspecialchars($iTitle) . '">' . IconUtility::getSpriteIcon('actions-document-open') . '</a>';
+                                               . '" title="' . htmlspecialchars($iTitle) . '">'
+                                               . $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL)->render() . '</a>';
                                } else {
                                        $eI = '';
                                }
@@ -351,9 +376,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                                if (substr($field, 0, 6) == 'table_') {
                                                        $f2 = substr($field, 6);
                                                        if ($GLOBALS['TCA'][$f2]) {
-                                                               $theData[$field] = '&nbsp;' . IconUtility::getSpriteIconForRecord($f2, array(), array(
-                                                                       'title' => $this->getLanguageService()->sL($GLOBALS['TCA'][$f2]['ctrl']['title'], TRUE)
-                                                                       ));
+                                                               $theData[$field] = '&nbsp;' . '<span title="' . $this->getLanguageService()->sL($GLOBALS['TCA'][$f2]['ctrl']['title'], TRUE) . '">' . $this->iconFactory->getIconForRecord($f2, array(), Icon::SIZE_SMALL)->render() . '</span>';
                                                        }
                                                } else {
                                                        $theData[$field] = '&nbsp;&nbsp;<strong>'
@@ -385,6 +408,8 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
         * @return string HTML for the listing
         */
        public function getTable_tt_content($id) {
+               $backendUser = $this->getBackendUser();
+               $this->pageinfo = BackendUtility::readPageAccess($this->id, $backendUser->getPagePermsClause($this->ext_CALC_PERMS));
                $this->initializeLanguages();
                $this->initializeClipboard();
                $pageTitleParamForAltDoc = '&recTitle=' . rawurlencode(BackendUtility::getRecordTitle('pages', BackendUtility::getRecordWSOL('pages', $id), TRUE));
@@ -392,7 +417,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                $pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
                $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LayoutModule/DragDrop');
                $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Modal');
-               $userCanEditPage = $this->ext_CALC_PERMS & Permission::PAGE_EDIT && !empty($this->id);
+               $userCanEditPage = $this->ext_CALC_PERMS & Permission::PAGE_EDIT && !empty($this->id) && ($backendUser->isAdmin() || (int)$this->pageinfo['editlock'] === 0);
                if ($this->tt_contentConfig['languageColsPointer'] > 0) {
                        $userCanEditPage = $this->getBackendUser()->check('tables_modify', 'pages_language_overlay');
                }
@@ -432,8 +457,8 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                foreach ($langListArr as $lP) {
                        $lP = (int)$lP;
 
-                       if (!isset($this->getPageLayoutController()->contentElementCache[$lP])) {
-                               $this->getPageLayoutController()->contentElementCache[$lP] = array();
+                       if (!isset($this->contentElementCache[$lP])) {
+                               $this->contentElementCache[$lP] = array();
                        }
 
                        if (count($langListArr) === 1 || $lP === 0) {
@@ -449,8 +474,8 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                        $contentRecordsPerColumn = $this->getContentRecordsPerColumn('table', $id, array_values($cList), $showLanguage);
                        // For each column, render the content into a variable:
                        foreach ($cList as $key) {
-                               if (!isset($this->getPageLayoutController()->contentElementCache[$lP][$key])) {
-                                       $this->getPageLayoutController()->contentElementCache[$lP][$key] = array();
+                               if (!isset($this->contentElementCache[$lP][$key])) {
+                                       $this->contentElementCache[$lP][$key] = array();
                                }
 
                                if (!$lP) {
@@ -467,13 +492,13 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                if ($this->getPageLayoutController()->pageIsNotLockedForEditors()) {
                                        $link = '<a href="#" onclick="' . htmlspecialchars($this->newContentElementOnClick($id, $key, $lP))
                                                . '" title="' . $this->getLanguageService()->getLL('newContentElement', TRUE) . '" class="btn btn-default btn-sm">'
-                                               . $this->iconFactory->getIcon('actions-document-new', Icon::SIZE_SMALL)
+                                               . $this->iconFactory->getIcon('actions-document-new', Icon::SIZE_SMALL)->render()
                                                . ' '
                                                . $this->getLanguageService()->getLL('content', TRUE) . '</a>';
                                }
                                $content[$key] .= '
-                               <div class="t3-page-ce t3js-page-ce" data-page="' . (int)$id . '" id="' . str_replace('.', '', uniqid('', TRUE)) . '">
-                                       <div class="t3js-page-new-ce t3-page-ce-wrapper-new-ce" id="colpos-' . $key . '-' . 'page-' . $id . '-' . uniqid('', TRUE) . '">'
+                               <div class="t3-page-ce t3js-page-ce" data-page="' . (int)$id . '" id="' . StringUtility::getUniqueId() . '">
+                                       <div class="t3js-page-new-ce t3-page-ce-wrapper-new-ce" id="colpos-' . $key . '-' . 'page-' . $id . '-' . StringUtility::getUniqueId() . '">'
                                                . $link
                                        . '</div>
                                        <div class="t3-page-ce-dropzone-available t3js-page-ce-dropzone-available"></div>
@@ -484,7 +509,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                $this->generateTtContentDataArray($rowArr);
 
                                foreach ((array)$rowArr as $rKey => $row) {
-                                       $this->getPageLayoutController()->contentElementCache[$lP][$key][$row['uid']] = $row;
+                                       $this->contentElementCache[$lP][$key][$row['uid']] = $row;
                                        if ($this->tt_contentConfig['languageMode']) {
                                                $languageColumn[$key][$lP] = $head[$key] . $content[$key];
                                                if (!$this->defLangBinding) {
@@ -503,7 +528,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                                $editUidList .= $row['uid'] . ',';
                                                $disableMoveAndNewButtons = $this->defLangBinding && $lP > 0;
                                                if (!$this->tt_contentConfig['languageMode']) {
-                                                       $singleElementHTML .= '<div class="t3-page-ce-dragitem" id="' . str_replace('.', '', uniqid('', TRUE)) . '">';
+                                                       $singleElementHTML .= '<div class="t3-page-ce-dragitem" id="' . StringUtility::getUniqueId() . '">';
                                                }
                                                $singleElementHTML .= $this->tt_content_drawHeader(
                                                        $row,
@@ -526,7 +551,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                                        $singleElementHTML .= '<div class="t3-page-ce t3js-page-ce">';
                                                }
                                                $singleElementHTML .= '<div class="t3js-page-new-ce t3-page-ce-wrapper-new-ce" id="colpos-' . $key . '-' . 'page-' . $id .
-                                                       '-' . str_replace('.', '', uniqid('', TRUE)) . '">';
+                                                       '-' . StringUtility::getUniqueId() . '">';
                                                // Add icon "new content element below"
                                                if (!$disableMoveAndNewButtons && $this->getPageLayoutController()->pageIsNotLockedForEditors()) {
                                                        // New content element:
@@ -542,7 +567,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                                        $singleElementHTML .= '
                                                                <a href="#" onclick="' . htmlspecialchars($onClick) . '" title="'
                                                                        . $this->getLanguageService()->getLL('newContentElement', TRUE) . '" class="btn btn-default btn-sm">'
-                                                                       . $this->iconFactory->getIcon('actions-document-new', Icon::SIZE_SMALL)
+                                                                       . $this->iconFactory->getIcon('actions-document-new', Icon::SIZE_SMALL)->render()
                                                                        . ' '
                                                                        . $this->getLanguageService()->getLL('content', TRUE) . '</a>
                                                        ';
@@ -687,7 +712,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                $viewLink = '';
                                if (!VersionState::cast($this->getPageLayoutController()->pageinfo['t3ver_state'])->equals(VersionState::DELETE_PLACEHOLDER)) {
                                        $onClick = BackendUtility::viewOnClick($this->id, '', BackendUtility::BEgetRootLine($this->id), '', '', ('&L=' . $lP));
-                                       $viewLink = '<a href="#" onclick="' . htmlspecialchars($onClick) . '" title="' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.showPage', TRUE) . '">' . $this->iconFactory->getIcon('actions-document-view', Icon::SIZE_SMALL) . '</a>';
+                                       $viewLink = '<a href="#" onclick="' . htmlspecialchars($onClick) . '" title="' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.showPage', TRUE) . '">' . $this->iconFactory->getIcon('actions-document-view', Icon::SIZE_SMALL)->render() . '</a>';
                                }
                                // Language overlay page header:
                                if ($lP) {
@@ -695,17 +720,27 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                        BackendUtility::workspaceOL('pages_language_overlay', $lpRecord);
                                        $params = '&edit[pages_language_overlay][' . $lpRecord['uid'] . ']=edit&overrideVals[pages_language_overlay][sys_language_uid]=' . $lP;
                                        $lPLabel = $this->getPageLayoutController()->doc->wrapClickMenuOnIcon(
-                                               IconUtility::getSpriteIconForRecord('pages_language_overlay', $lpRecord),
+                                               $this->iconFactory->getIconForRecord('pages_language_overlay', $lpRecord, Icon::SIZE_SMALL)->render(),
                                                'pages_language_overlay',
                                                $lpRecord['uid']
                                        ) . $viewLink . ($this->getBackendUser()->check('tables_modify', 'pages_language_overlay')
                                                        ? '<a href="#" onclick="' . htmlspecialchars(BackendUtility::editOnClick($params))
                                                                . '" title="' . $this->getLanguageService()->getLL('edit', TRUE) . '">'
-                                                               . IconUtility::getSpriteIcon('actions-document-open') . '</a>'
+                                                               . $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL)->render() . '</a>'
                                                        : ''
                                                ) . htmlspecialchars(GeneralUtility::fixed_lgd_cs($lpRecord['title'], 20));
                                } else {
-                                       $lPLabel = $viewLink;
+                                       $params = '&edit[pages][' . $this->id . ']=edit';
+                                       $lPLabel = $this->getPageLayoutController()->doc->wrapClickMenuOnIcon(
+                                                       $this->iconFactory->getIconForRecord('pages', $this->pageRecord, Icon::SIZE_SMALL)->render(),
+                                                       'pages',
+                                                       $this->id
+                                               ) . $viewLink . ($this->getBackendUser()->check('tables_modify', 'pages_language_overlay')
+                                                       ? '<a href="#" onclick="' . htmlspecialchars(BackendUtility::editOnClick($params))
+                                                       . '" title="' . $this->getLanguageService()->getLL('edit', TRUE) . '">'
+                                                       . $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL)->render() . '</a>'
+                                                       : ''
+                                               ) . htmlspecialchars(GeneralUtility::fixed_lgd_cs($this->pageRecord['title'], 20));
                                }
                                $sCont[$lP] = '
                                        <td nowrap="nowrap" class="t3-page-column t3-page-lang-label">' . $lPLabel . '</td>';
@@ -802,7 +837,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                        $onClick = BackendUtility::editOnClick('&edit[' . $table . '][' . $this->id . ']=new');
                        $theData['__cmds__'] = '<a href="#" onclick="' . htmlspecialchars($onClick) . '" '
                                . 'title="' . $this->getLanguageService()->getLL('new', TRUE) . '">'
-                               . $this->iconFactory->getIcon('actions-document-new', Icon::SIZE_SMALL) . '</a>';
+                               . $this->iconFactory->getIcon('actions-document-new', Icon::SIZE_SMALL)->render() . '</a>';
                }
                $out .= $this->addelement(1, '', $theData, ' class="c-headLine"', 15, '', 'th');
                // Render Items
@@ -825,7 +860,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                        if ($this->doEdit) {
                                                $Nrow['__editIconLink__'] = '<a href="#" onclick="' . htmlspecialchars(BackendUtility::editOnClick($params))
                                                        . '" title="' . $this->getLanguageService()->getLL('edit', TRUE) . '">'
-                                                       . IconUtility::getSpriteIcon('actions-document-open') . '</a>';
+                                                       . $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL)->render() . '</a>';
                                        } else {
                                                $Nrow['__editIconLink__'] = $this->noEditIcon();
                                        }
@@ -1030,7 +1065,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                                $eI = '<a href="#" onclick="'
                                                        . htmlspecialchars(BackendUtility::editOnClick($params))
                                                        . '" title="' . $this->getLanguageService()->getLL('editThisPage', TRUE) . '">'
-                                                       . IconUtility::getSpriteIcon('actions-document-open') . '</a>';
+                                                       . $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL)->render() . '</a>';
                                        } else {
                                                $eI = '';
                                        }
@@ -1093,17 +1128,17 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                $iconsArr['edit'] = '<a href="#" onclick="'
                                        . htmlspecialchars(BackendUtility::editOnClick($editParams)) . '" title="'
                                        . $this->getLanguageService()->getLL('editColumn', TRUE) . '">'
-                                       . IconUtility::getSpriteIcon('actions-document-open') . '</a>';
+                                       . $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL)->render() . '</a>';
                        }
                        if ($pasteParams) {
                                $elFromTable = $this->clipboard->elFromTable('tt_content');
-                               if (!empty($elFromTable)) {
+                               if (!empty($elFromTable) && $this->getPageLayoutController()->pageIsNotLockedForEditors()) {
                                        $iconsArr['paste'] = '<a href="'
                                                . htmlspecialchars($this->clipboard->pasteUrl('tt_content', $this->id, TRUE, $pasteParams))
                                                . '" onclick="' . htmlspecialchars(('return '
                                                . $this->clipboard->confirmMsg('pages', $this->pageRecord, 'into', $elFromTable, $colName)))
                                                . '" title="' . $this->getLanguageService()->getLL('pasteIntoColumn', TRUE) . '">'
-                                               . $this->iconFactory->getIcon('actions-document-paste-into', Icon::SIZE_SMALL) . '</a>';
+                                               . $this->iconFactory->getIcon('actions-document-paste-into', Icon::SIZE_SMALL)->render() . '</a>';
                                }
                        }
                }
@@ -1187,7 +1222,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                        )) . '" title="' . htmlspecialchars($this->nextThree > 1
                                                ? sprintf($this->getLanguageService()->getLL('nextThree'), $this->nextThree)
                                                : $this->getLanguageService()->getLL('edit'))
-                                       . '">' . IconUtility::getSpriteIcon('actions-document-open') . '</a>';
+                                       . '">' . $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL)->render() . '</a>';
                                // Hide element:
                                $hiddenField = $GLOBALS['TCA']['tt_content']['ctrl']['enablecolumns']['disabled'];
                                if (
@@ -1206,7 +1241,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                                . '][' . $hiddenField . ']=' . $value;
                                        $out .= '<a class="btn btn-default" href="' . htmlspecialchars($this->getPageLayoutController()->doc->issueCommand($params))
                                                . '" title="' . $this->getLanguageService()->getLL($label, TRUE) . '">'
-                                               . IconUtility::getSpriteIcon('actions-edit-' . strtolower($label)) . '</a>';
+                                               . $this->iconFactory->getIcon('actions-edit-' . strtolower($label), Icon::SIZE_SMALL)->render() . '</a>';
                                }
                                // Delete
                                $params = '&cmd[tt_content][' . $row['uid'] . '][delete]=1';
@@ -1220,7 +1255,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                        . ' data-content="' . htmlspecialchars($confirm) . '" '
                                        . ' data-button-close-text="' . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/locallang_common.xlf:cancel')) . '"'
                                        . ' title="' . $this->getLanguageService()->getLL('deleteItem', TRUE) . '">'
-                                       . $this->iconFactory->getIcon('actions-edit-delete', Icon::SIZE_SMALL) . '</a>';
+                                       . $this->iconFactory->getIcon('actions-edit-delete', Icon::SIZE_SMALL)->render() . '</a>';
                                if ($out) {
                                        $out = '<div class="btn-group btn-group-sm" role="group">' . $out . '</div>';
                                }
@@ -1233,12 +1268,12 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                                $moveButtonContent .= '<a class="btn btn-default" href="'
                                                        . htmlspecialchars($this->getPageLayoutController()->doc->issueCommand($params))
                                                        . '" title="' . $this->getLanguageService()->getLL('moveUp', TRUE) . '">'
-                                                       . IconUtility::getSpriteIcon('actions-move-up') . '</a>';
+                                                       . $this->iconFactory->getIcon('actions-move-up', Icon::SIZE_SMALL)->render() . '</a>';
                                                if (!$dragDropEnabled) {
                                                        $displayMoveButtons = TRUE;
                                                }
                                        } else {
-                                               $moveButtonContent .= '<span class="btn btn-default disabled">' . IconUtility::getSpriteIcon('empty-empty') . '</span>';
+                                               $moveButtonContent .= '<span class="btn btn-default disabled">' . $this->iconFactory->getIcon('empty-empty', Icon::SIZE_SMALL)->render() . '</span>';
                                        }
                                        // Move element down:
                                        if ($this->tt_contentData['next'][$row['uid']]) {
@@ -1246,12 +1281,12 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                                $moveButtonContent .= '<a class="btn btn-default" href="'
                                                        . htmlspecialchars($this->getPageLayoutController()->doc->issueCommand($params))
                                                        . '" title="' . $this->getLanguageService()->getLL('moveDown', TRUE) . '">'
-                                                       . IconUtility::getSpriteIcon('actions-move-down') . '</a>';
+                                                       . $this->iconFactory->getIcon('actions-move-down', Icon::SIZE_SMALL)->render() . '</a>';
                                                if (!$dragDropEnabled) {
                                                        $displayMoveButtons = TRUE;
                                                }
                                        } else {
-                                               $moveButtonContent .= '<span class="btn btn-default disabled">' . IconUtility::getSpriteIcon('empty-empty') . '</span>';
+                                               $moveButtonContent .= '<span class="btn btn-default disabled">' . $this->iconFactory->getIcon('empty-empty', Icon::SIZE_SMALL)->render() . '</span>';
                                        }
                                        if ($displayMoveButtons) {
                                                $out .= '<div class="btn-group btn-group-sm" role="group">' . $moveButtonContent . '</div>';
@@ -1266,7 +1301,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                if ($lockInfo = BackendUtility::isRecordLocked('tt_content', $row['uid'])) {
                        $additionalIcons[] = '<a href="#" onclick="alert(' . GeneralUtility::quoteJSvalue($lockInfo['msg'])
                                . ');return false;" title="' . htmlspecialchars($lockInfo['msg']) . '">'
-                               . IconUtility::getSpriteIcon('status-warning-in-use') . '</a>';
+                               . $this->iconFactory->getIcon('status-warning-in-use', Icon::SIZE_SMALL)->render() . '</a>';
                }
                // Call stats information hook
                if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['recStatInfoHooks'])) {
@@ -1277,7 +1312,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                }
                // Wrap the whole header
                // NOTE: end-tag for <div class="t3-page-ce-body"> is in getTable_tt_content()
-               return '<div class="t3-page-ce-header ' . ($this->getBackendUser()->user['admin'] || (int)$row['editlock'] === 0 ? 't3-page-ce-header-draggable t3js-page-ce-draghandle' : '') . '">
+               return '<div class="t3-page-ce-header ' . ($this->getBackendUser()->user['admin'] || ((int)$row['editlock'] === 0 && (int)$this->pageinfo['editlock'] === 0)  ? 't3-page-ce-header-draggable t3js-page-ce-draghandle' : '') . '">
                                        <div class="t3-page-ce-header-icons-left">' . implode('', $additionalIcons) . '</div>
                                        <div class="t3-page-ce-header-icons-right">' . ($out ? '<div class="btn-toolbar">' .$out . '</div>' : '') . '</div>
                                </div>
@@ -1324,6 +1359,36 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                $hookObject->preProcess($this, $drawItem, $outHeader, $out, $row);
                        }
                }
+
+               // If the previous hook did not render something,
+               // then check if a Fluid-based preview template was defined for this CType
+               // and render it via Fluid. Possible option:
+               // mod.web_layout.tt_content.preview.media = EXT:site_mysite/Resources/Private/Templates/Preview/Media.html
+               if ($drawItem) {
+                       $tsConfig = BackendUtility::getModTSconfig($row['pid'], 'mod.web_layout.tt_content.preview');
+                       if (!empty($tsConfig['properties'][$row['CType']])) {
+                               $fluidTemplateFile = $tsConfig['properties'][$row['CType']];
+                               $fluidTemplateFile = GeneralUtility::getFileAbsFileName($fluidTemplateFile);
+                               if ($fluidTemplateFile) {
+                                       try {
+                                               /** @var StandaloneView $view */
+                                               $view = GeneralUtility::makeInstance(StandaloneView::class);
+                                               $view->setTemplatePathAndFilename($fluidTemplateFile);
+                                               $view->assignMultiple($row);
+                                               if (!empty($row['pi_flexform'])) {
+                                                       /** @var FlexFormService $flexFormService */
+                                                       $flexFormService = GeneralUtility::makeInstance(FlexFormService::class);
+                                                       $view->assign('pi_flexform_transformed', $flexFormService->convertFlexFormContentToArray($row['pi_flexform']));
+                                               }
+                                               $out = $view->render();
+                                               $drawItem = FALSE;
+                                       } catch (\Exception $e) {
+                                               // Catch any exception to avoid breaking the view
+                                       }
+                               }
+                       }
+               }
+
                // Draw preview of the item depending on its CType (if not disabled by previous hook):
                if ($drawItem) {
                        switch ($row['CType']) {
@@ -1366,7 +1431,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                                        $tableName = empty($split[0]) ? 'tt_content' : $split[0];
                                                        $shortcutRecord = BackendUtility::getRecord($tableName, $split[1]);
                                                        if (is_array($shortcutRecord)) {
-                                                               $icon = IconUtility::getSpriteIconForRecord($tableName, $shortcutRecord);
+                                                               $icon = $this->iconFactory->getIconForRecord($tableName, $shortcutRecord, Icon::SIZE_SMALL)->render();
                                                                $icon = $this->getPageLayoutController()->doc->wrapClickMenuOnIcon($icon, $tableName,
                                                                        $shortcutRecord['uid'], 1, '', '+copy,info,edit,view');
                                                                $shortcutContent[] = $icon
@@ -1527,7 +1592,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
 
                $copyFromLanguageMenu = '';
                foreach ($this->getLanguagesToCopyFrom(GeneralUtility::_GP('id'), $lP, $colPos) as $languageId => $label) {
-                       $elementsInColumn = $languageId === 0 ? $defLanguageCount : $this->getPageLayoutController()->getElementsFromColumnAndLanguage(GeneralUtility::_GP('id'), $colPos, $languageId);
+                       $elementsInColumn = $languageId === 0 ? $defLanguageCount : $this->getElementsFromColumnAndLanguage(GeneralUtility::_GP('id'), $colPos, $languageId);
                        if (!empty($elementsInColumn)) {
                                $onClick = 'window.location.href=' . GeneralUtility::quoteJSvalue($this->getPageLayoutController()->doc->issueCommand('&cmd[tt_content][' . implode(',', $elementsInColumn) . '][copyFromLanguage]=' . GeneralUtility::_GP('id') . ',' . $lP)) . '; return false;';
                                $copyFromLanguageMenu .= '<li><a href="#" onclick="' . htmlspecialchars($onClick) . '">' . $this->languageFlag($languageId, FALSE) . ' ' . htmlspecialchars($label) . '</a></li>' . LF;
@@ -1554,7 +1619,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                                $onClick,
                                                $this->getLanguageService()->getLL('newPageContent_copyForLang', TRUE) . ' [' . count($defLanguageCount) . ']'
                                        );
-                       if ($copyFromLanguageMenu !== '' && $this->getPageLayoutController()->isColumnEmpty($colPos, $lP)) {
+                       if ($copyFromLanguageMenu !== '' && $this->isColumnEmpty($colPos, $lP)) {
                                $theNewButton .= '<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">'
                                        . '<span class="caret"></span>'
                                        . '<span class="sr-only">Toggle Dropdown</span>'
@@ -1563,7 +1628,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                        }
                        $theNewButton .= '</div>';
                } else {
-                       if ($copyFromLanguageMenu !== '' && $this->getPageLayoutController()->isColumnEmpty($colPos, $lP)) {
+                       if ($copyFromLanguageMenu !== '' && $this->isColumnEmpty($colPos, $lP)) {
                                $theNewButton =
                                        '<div class="btn-group">'
                                        . '<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">'
@@ -1678,11 +1743,11 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
         */
        protected function getLanguagesToCopyFrom($pageId, $excludeLanguage = NULL, $colPos = 0) {
                $langSelItems = array();
-               if (!$this->getPageLayoutController()->isColumnEmpty($colPos, 0)) {
+               if (!$this->isColumnEmpty($colPos, 0)) {
                        $langSelItems[0] = $this->getLanguageService()->getLL('newPageContent_translateFromDefault', TRUE);
                }
 
-               $languages = $this->getPageLayoutController()->getUsedLanguagesInPageAndColumn($pageId, $colPos);
+               $languages = $this->getUsedLanguagesInPageAndColumn($pageId, $colPos);
                foreach ($languages as $uid => $language) {
                        $langSelItems[$uid] = sprintf($this->getLanguageService()->getLL('newPageContent_copyFromAnotherLang'), htmlspecialchars($language['title']));
                }
@@ -1695,6 +1760,92 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
        }
 
        /**
+        * Get used languages in a colPos of a page
+        *
+        * @param int $pageId
+        * @param int $colPos
+        * @return bool|\mysqli_result|object
+        */
+       protected function getUsedLanguagesInPageAndColumn($pageId, $colPos) {
+               if (!isset($this->languagesInColumnCache[$pageId])) {
+                       $this->languagesInColumnCache[$pageId] = array();
+               }
+               if (!isset($this->languagesInColumnCache[$pageId][$colPos])) {
+                       $this->languagesInColumnCache[$pageId][$colPos] = array();
+               }
+
+               if (empty($this->languagesInColumnCache[$pageId][$colPos])) {
+                       $exQ = BackendUtility::deleteClause('tt_content') .
+                               ($this->getBackendUser()->isAdmin() ? '' : ' AND sys_language.hidden=0');
+
+                       $databaseConnection = $this->getDatabaseConnection();
+                       $res = $databaseConnection->exec_SELECTquery(
+                               'sys_language.*',
+                               'tt_content,sys_language',
+                               'tt_content.sys_language_uid=sys_language.uid AND tt_content.colPos = ' . (int)$colPos . ' AND tt_content.pid=' . (int)$pageId . $exQ .
+                               BackendUtility::versioningPlaceholderClause('tt_content'),
+                               'tt_content.sys_language_uid,sys_language.uid,sys_language.pid,sys_language.tstamp,sys_language.hidden,sys_language.title,sys_language.language_isocode,sys_language.static_lang_isocode,sys_language.flag',
+                               'sys_language.title'
+                       );
+                       while ($row = $databaseConnection->sql_fetch_assoc($res)) {
+                               $this->languagesInColumnCache[$pageId][$colPos][$row['uid']] = $row;
+                       }
+                       $databaseConnection->sql_free_result($res);
+               }
+
+               return $this->languagesInColumnCache[$pageId][$colPos];
+       }
+
+       /**
+        * Check if a column of a page for a language is empty. Translation records are ignored here!
+        *
+        * @param int $colPos
+        * @param int $languageId
+        * @return bool
+        */
+       protected function isColumnEmpty($colPos, $languageId) {
+               foreach ($this->contentElementCache[$languageId][$colPos] as $uid => $row) {
+                       if ((int)$row['l18n_parent'] === 0) {
+                               return FALSE;
+                       }
+               }
+               return TRUE;
+       }
+
+       /**
+        * Get elements for a column and a language
+        *
+        * @param int $pageId
+        * @param int $colPos
+        * @param int $languageId
+        * @return array
+        */
+       protected function getElementsFromColumnAndLanguage($pageId, $colPos, $languageId) {
+               if (!isset($this->contentElementCache[$languageId][$colPos])) {
+                       $languageId = (int)$languageId;
+                       $whereClause = 'tt_content.pid=' . (int)$pageId . ' AND tt_content.colPos=' . (int)$colPos . ' AND tt_content.sys_language_uid=' . $languageId . BackendUtility::deleteClause('tt_content');
+                       if ($languageId > 0) {
+                               $whereClause .= ' AND tt_content.l18n_parent=0 AND sys_language.uid=' . $languageId . ($this->getBackendUser()->isAdmin() ? '' : ' AND sys_language.hidden=0');
+                       }
+
+                       $databaseConnection = $this->getDatabaseConnection();
+                       $res = $databaseConnection->exec_SELECTquery(
+                               'tt_content.uid',
+                               'tt_content,sys_language',
+                               $whereClause
+                       );
+                       while ($row = $databaseConnection->sql_fetch_assoc($res)) {
+                               $this->contentElementCache[$languageId][$colPos][$row['uid']] = $row;
+                       }
+                       $databaseConnection->sql_free_result($res);
+               }
+               if (is_array($this->contentElementCache[$languageId][$colPos])) {
+                       return array_keys($this->contentElementCache[$languageId][$colPos]);
+               }
+               return array();
+       }
+
+       /**
         * Make selector box for creating new translation in a language
         * Displays only languages which are not yet present for the current page and
         * that are not disabled with page TS.
@@ -1896,7 +2047,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
        public function getIcon($table, $row) {
                // Initialization
                $altText = BackendUtility::getRecordIconAltText($row, $table);
-               $icon = IconUtility::getSpriteIconForRecord($table, $row, array('title' => $altText));
+               $icon = '<span title="' . $altText . '">' . $this->iconFactory->getIconForRecord($table, $row, Icon::SIZE_SMALL)->render() . '</span>';
                $this->counter++;
                // The icon with link
                if ($this->getBackendUser()->recordEditAccessInternals($table, $row)) {
@@ -1950,10 +2101,8 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
         * @return string IMG tag for icon.
         */
        public function noEditIcon($label = 'noEditItems') {
-               return IconUtility::getSpriteIcon(
-                       'status-edit-read-only',
-                       array('title' => $this->getLanguageService()->getLL($label, TRUE))
-               );
+               $title = $this->getLanguageService()->getLL($label, TRUE);
+               return '<span title="' . $title . '">' . $this->iconFactory->getIcon('status-status-edit-read-only', Icon::SIZE_SMALL)->render() . '</span>';
        }
 
        /**
@@ -2025,18 +2174,16 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                if ($c || GeneralUtility::inList('tt_content', $tName)) {
                                        // Add row to menu:
                                        $out .= '
-                                       <td><a href="#' . $tName . '"></a>' . IconUtility::getSpriteIconForRecord(
-                                                       $tName,
-                                                       array(),
-                                                       array('title' => $this->getLanguageService()->sL($GLOBALS['TCA'][$tName]['ctrl']['title'], TRUE))
-                                               ) . '</td>';
+                                       <td><a href="#' . $tName . '" title="' . $this->getLanguageService()->sL($GLOBALS['TCA'][$tName]['ctrl']['title'], TRUE) . '"></a>'
+                                               . $this->iconFactory->getIconForRecord($tName, array(), Icon::SIZE_SMALL)->render()
+                                               . '</td>';
                                        // ... and to the internal array, activeTables we also add table icon and title (for use elsewhere)
-                                       $this->activeTables[$tName] = IconUtility::getSpriteIconForRecord(
-                                                       $tName,
-                                                       array(),
-                                                       array('title' => $this->getLanguageService()->sL($GLOBALS['TCA'][$tName]['ctrl']['title'], TRUE)
-                                                                       . ': ' . $c . ' ' . $this->getLanguageService()->getLL('records', TRUE))
-                                               . '&nbsp;' . $this->getLanguageService()->sL($GLOBALS['TCA'][$tName]['ctrl']['title'], TRUE);
+                                       $title = $this->getLanguageService()->sL($GLOBALS['TCA'][$tName]['ctrl']['title'], TRUE)
+                                               . ': ' . $c . ' ' . $this->getLanguageService()->getLL('records', TRUE);
+                                       $this->activeTables[$tName] = '<span title="' . $title. '">'
+                                               . $this->iconFactory->getIconForRecord($tName, array(), Icon::SIZE_SMALL)->render()
+                                               . '</span>'
+                                               . '&nbsp;' . $this->getLanguageService()->sL($GLOBALS['TCA'][$tName]['ctrl']['title'], TRUE);
                                }
                        }
                }