[TASK] Call explicit render() on icon objects
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / View / PageLayoutView.php
index 69f30f7..155e2b2 100644 (file)
@@ -16,19 +16,21 @@ 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;
+use TYPO3\CMS\Core\Imaging\IconFactory;
 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
- *
- * @author Kasper Skårhøj <kasperYYYY@typo3.com>
  */
 class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRecordList {
 
@@ -172,6 +174,40 @@ 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;
+
+       /**
+        * Construct to initialize class variables.
+        */
+       public function __construct() {
+               $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
+       }
+
        /*****************************************
         *
         * Renderings
@@ -182,9 +218,10 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
         *
         * @param string $table Table name
         * @param int $id Current page id
+        * @param string $fields
         * @return string HTML for listing.
         */
-       public function getTable($table, $id) {
+       public function getTable($table, $id, $fields = '') {
                if (isset($this->externalTables[$table])) {
                        return $this->getExternalTables($id, $table);
                } else {
@@ -321,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 = '';
                                }
@@ -338,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>'
@@ -372,13 +408,16 @@ 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));
                /** @var $pageRenderer PageRenderer */
                $pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
                $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LayoutModule/DragDrop');
-               $userCanEditPage = $this->ext_CALC_PERMS & Permission::PAGE_EDIT && !empty($this->id);
+               $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Modal');
+               $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');
                }
@@ -417,6 +456,11 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                // If not languageMode, then we'll only be through this once.
                foreach ($langListArr as $lP) {
                        $lP = (int)$lP;
+
+                       if (!isset($this->contentElementCache[$lP])) {
+                               $this->contentElementCache[$lP] = array();
+                       }
+
                        if (count($langListArr) === 1 || $lP === 0) {
                                $showLanguage = ' AND sys_language_uid IN (' . $lP . ',-1)';
                        } else {
@@ -430,6 +474,10 @@ 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->contentElementCache[$lP][$key])) {
+                                       $this->contentElementCache[$lP][$key] = array();
+                               }
+
                                if (!$lP) {
                                        $defLanguageCount[$key] = array();
                                }
@@ -440,40 +488,47 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                }
                                $content[$key] .= '">';
                                // Add new content at the top most position
+                               $link = '';
+                               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)->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) . '">
-                                               <a href="#" onclick="' . htmlspecialchars($this->newContentElementOnClick($id, $key, $lP))
-                                                       . '" title="' . $this->getLanguageService()->getLL('newContentElement', TRUE) . '" class="btn btn-default btn-sm">'
-                                                       . IconUtility::getSpriteIcon('actions-document-new')
-                                                       . ' '
-                                                       . $this->getLanguageService()->getLL('content', TRUE) . '</a>
-                                       </div>
+                               <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>
                                </div>
                                ';
                                $editUidList = '';
                                $rowArr = $contentRecordsPerColumn[$key];
                                $this->generateTtContentDataArray($rowArr);
+
                                foreach ((array)$rowArr as $rKey => $row) {
+                                       $this->contentElementCache[$lP][$key][$row['uid']] = $row;
                                        if ($this->tt_contentConfig['languageMode']) {
                                                $languageColumn[$key][$lP] = $head[$key] . $content[$key];
                                                if (!$this->defLangBinding) {
                                                        $languageColumn[$key][$lP] .= $this->newLanguageButton(
                                                                $this->getNonTranslatedTTcontentUids($defLanguageCount[$key], $id, $lP),
-                                                               $lP
+                                                               $lP,
+                                                               $key
                                                        );
                                                }
                                        }
                                        if (is_array($row) && !VersionState::cast($row['t3ver_state'])->equals(VersionState::DELETE_PLACEHOLDER)) {
                                                $singleElementHTML = '';
                                                if (!$lP && ($this->defLangBinding || $row['sys_language_uid'] != -1)) {
-                                                       $defLanguageCount[$key][] = $row['uid'];
+                                                       $defLanguageCount[$key][] = (isset($row['_ORIG_uid']) ? $row['_ORIG_uid'] : $row['uid']);
                                                }
                                                $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,
@@ -496,9 +551,9 @@ 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) {
+                                               if (!$disableMoveAndNewButtons && $this->getPageLayoutController()->pageIsNotLockedForEditors()) {
                                                        // New content element:
                                                        if ($this->option_newWizard) {
                                                                $onClick = 'window.location.href=' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('new_content_element') . '&id=' . $row['pid']
@@ -507,12 +562,12 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                                                        '&returnUrl=' . rawurlencode(GeneralUtility::getIndpEnv('REQUEST_URI'))) . ';';
                                                        } else {
                                                                $params = '&edit[tt_content][' . -$row['uid'] . ']=new';
-                                                               $onClick = BackendUtility::editOnClick($params, $this->backPath);
+                                                               $onClick = BackendUtility::editOnClick($params);
                                                        }
                                                        $singleElementHTML .= '
                                                                <a href="#" onclick="' . htmlspecialchars($onClick) . '" title="'
                                                                        . $this->getLanguageService()->getLL('newContentElement', TRUE) . '" class="btn btn-default btn-sm">'
-                                                                       . IconUtility::getSpriteIcon('actions-document-new')
+                                                                       . $this->iconFactory->getIcon('actions-document-new', Icon::SIZE_SMALL)->render()
                                                                        . ' '
                                                                        . $this->getLanguageService()->getLL('content', TRUE) . '</a>
                                                        ';
@@ -554,7 +609,8 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                        if (!$this->defLangBinding) {
                                                $languageColumn[$key][$lP] .= $this->newLanguageButton(
                                                        $this->getNonTranslatedTTcontentUids($defLanguageCount[$key], $id, $lP),
-                                                       $lP
+                                                       $lP,
+                                                       $key
                                                );
                                        }
                                        // We sort $languageColumn again according to $cList as it may contain data already from above.
@@ -655,8 +711,8 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                // "View page" icon is added:
                                $viewLink = '';
                                if (!VersionState::cast($this->getPageLayoutController()->pageinfo['t3ver_state'])->equals(VersionState::DELETE_PLACEHOLDER)) {
-                                       $onClick = BackendUtility::viewOnClick($this->id, $this->backPath, 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) . '">' . IconUtility::getSpriteIcon('actions-document-view') . '</a>';
+                                       $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)->render() . '</a>';
                                }
                                // Language overlay page header:
                                if ($lP) {
@@ -664,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>';
@@ -698,7 +764,8 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                                foreach ($langListArr as $lP) {
                                                        $cCont[] = $defLangBinding[$cKey][$lP][$defUid] . $this->newLanguageButton(
                                                                $this->getNonTranslatedTTcontentUids(array($defUid), $id, $lP),
-                                                               $lP
+                                                               $lP,
+                                                               $cKey
                                                        );
                                                }
                                                $out .= '
@@ -770,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) . '">'
-                               . IconUtility::getSpriteIcon('actions-document-new') . '</a>';
+                               . $this->iconFactory->getIcon('actions-document-new', Icon::SIZE_SMALL)->render() . '</a>';
                }
                $out .= $this->addelement(1, '', $theData, ' class="c-headLine"', 15, '', 'th');
                // Render Items
@@ -793,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();
                                        }
@@ -947,18 +1014,10 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                BackendUtility::workspaceOL('pages', $row);
                                if (is_array($row)) {
                                        $c++;
-                                       $row['treeIcons'] = $treeIcons . '<img' . IconUtility::skinImg(
-                                                       $this->backPath,
-                                                       'gfx/ol/join' . ($rc == $c ? 'bottom' : '') . '.gif',
-                                                       'width="18" height="16"'
-                                               ) . ' alt="" />';
+                                       $row['treeIcons'] = $treeIcons . '<span class="treeline-icon treeline-icon-join' . ($rc === $c ? 'bottom' : '') . '"></span>';
                                        $theRows[] = $row;
                                        // Get the branch
-                                       $spaceOutIcons = '<img' . IconUtility::skinImg(
-                                                       $this->backPath,
-                                                       'gfx/ol/' . ($rc == $c ? 'blank.gif' : 'line.gif'),
-                                                       'width="18" height="16"'
-                                               ) . ' alt="" />';
+                                       $spaceOutIcons = '<span class="treeline-icon treeline-icon-' . ($rc === $c ? 'clear' : 'line') . '"></span>';
                                        $theRows = $this->pages_getTree($theRows, $row['uid'], $qWhere, $treeIcons . $spaceOutIcons, $row['php_tree_stop'] ? 0 : $depth);
                                }
                        }
@@ -986,7 +1045,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                foreach ($fieldArr as $field) {
                        switch ($field) {
                                case 'title':
-                                       $red = $this->plusPages[$row['uid']] ? '<font color="red"><strong>+&nbsp;</strong></font>' : '';
+                                       $red = $this->plusPages[$row['uid']] ? '<span class="text-danger"><strong>+</strong></span>' : '';
                                        $pTitle = htmlspecialchars(BackendUtility::getProcessedValue('pages', $field, $row[$field], 20));
                                        if ($red) {
                                                $pTitle = '<a href="'
@@ -1006,12 +1065,18 @@ 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 = '';
                                        }
                                        $theData[$field] = '<span align="right">' . $row['uid'] . $eI . '</span>';
                                        break;
+                               case 'shortcut':
+                               case 'shortcut_mode':
+                                       if ((int)$row['doktype'] === \TYPO3\CMS\Frontend\Page\PageRepository::DOKTYPE_SHORTCUT) {
+                                               $theData[$field] = $this->getPagesTableFieldValue($field, $row);
+                                       }
+                                       break;
                                default:
                                        if (substr($field, 0, 6) == 'table_') {
                                                $f2 = substr($field, 6);
@@ -1020,8 +1085,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                                        $theData[$field] = '&nbsp;&nbsp;' . ($c ? $c : '');
                                                }
                                        } else {
-                                               $theData[$field] = '&nbsp;&nbsp;'
-                                                       . htmlspecialchars(BackendUtility::getProcessedValue('pages', $field, $row[$field]));
+                                               $theData[$field] = $this->getPagesTableFieldValue($field, $row);
                                        }
                        }
                }
@@ -1029,6 +1093,18 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                return $this->addelement(1, '', $theData);
        }
 
+       /**
+        * Returns the HTML code for rendering a field in the pages table.
+        * The row value is processed to a human readable form and the result is parsed through htmlspecialchars().
+        *
+        * @param string $field The name of the field of which the value should be rendered.
+        * @param array $row The pages table row as an associative array.
+        * @return string The rendered table field value.
+        */
+       protected function getPagesTableFieldValue($field, array $row) {
+               return '&nbsp;&nbsp;' . htmlspecialchars(BackendUtility::getProcessedValue('pages', $field, $row[$field]));
+       }
+
        /**********************************
         *
         * Additional functions; Content Elements
@@ -1052,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('clip_paste', TRUE) . '">'
-                                               . IconUtility::getSpriteIcon('actions-document-paste-into') . '</a>';
+                                               . '" title="' . $this->getLanguageService()->getLL('pasteIntoColumn', TRUE) . '">'
+                                               . $this->iconFactory->getIcon('actions-document-paste-into', Icon::SIZE_SMALL)->render() . '</a>';
                                }
                        }
                }
@@ -1091,7 +1167,12 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                $info = array();
                $this->getProcessedValue('tt_content', 'starttime,endtime,fe_group,spaceBefore,spaceAfter', $row, $info);
 
-               // Call drawFooter hooks
+               // Content element annotation
+               if (!empty($GLOBALS['TCA']['tt_content']['ctrl']['descriptionColumn'])) {
+                       $info[] = htmlspecialchars($row[$GLOBALS['TCA']['tt_content']['ctrl']['descriptionColumn']]);
+               }
+
+                       // Call drawFooter hooks
                $drawFooterHooks = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/class.tx_cms_layout.php']['tt_content_drawFooter'];
                if (is_array($drawFooterHooks)) {
                        foreach ($drawFooterHooks as $hookClass) {
@@ -1141,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 (
@@ -1160,18 +1241,21 @@ 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';
-                               $confirm = GeneralUtility::quoteJSvalue($this->getLanguageService()->getLL('deleteWarning')
+                               $confirm = $this->getLanguageService()->getLL('deleteWarning')
                                        . BackendUtility::translationCount('tt_content', $row['uid'], (' '
-                                               . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.translationsOfRecord')))
+                                       . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.translationsOfRecord'))
                                );
-                               $out .= '<a class="btn btn-default" href="' . htmlspecialchars($this->getPageLayoutController()->doc->issueCommand($params))
-                                       . '" onclick="' . htmlspecialchars(('return confirm(' . $confirm . ');')) . '" title="'
-                                       . $this->getLanguageService()->getLL('deleteItem', TRUE) . '">'
-                                       . IconUtility::getSpriteIcon('actions-edit-delete') . '</a>';
+                               $out .= '<a class="btn btn-default t3js-modal-trigger" href="' . htmlspecialchars($this->getPageLayoutController()->doc->issueCommand($params)) . '"'
+                                       . ' data-severity="warning"'
+                                       . ' data-title="' . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:lang/locallang_alt_doc.xlf:label.confirm.delete_record.title')) . '"'
+                                       . ' 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)->render() . '</a>';
                                if ($out) {
                                        $out = '<div class="btn-group btn-group-sm" role="group">' . $out . '</div>';
                                }
@@ -1184,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']]) {
@@ -1197,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>';
@@ -1217,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'])) {
@@ -1228,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 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>
@@ -1246,6 +1330,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                $out = '';
                $outHeader = '';
                // Make header:
+
                if ($row['header']) {
                        $infoArr = array();
                        $this->getProcessedValue('tt_content', 'header_position,header_layout,header_link', $row, $infoArr);
@@ -1274,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']) {
@@ -1316,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
@@ -1444,14 +1559,16 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
        public function getNonTranslatedTTcontentUids($defLanguageCount, $id, $lP) {
                if ($lP && !empty($defLanguageCount)) {
                        // Select all translations here:
-                       $queryParts = $this->makeQueryArray('tt_content', $id, 'AND sys_language_uid=' . (int)$lP
-                               . ' AND l18n_parent IN (' . implode(',', $defLanguageCount) . ')');
-                       $result = $this->getDatabase()->exec_SELECT_queryArray($queryParts);
+                       $where = 'sys_language_uid=' . intval($lP) . ' AND l18n_parent IN ('
+                               . implode(',', $defLanguageCount) . ')'
+                               . BackendUtility::deleteClause('tt_content');
+                       $rowArr = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('*', 'tt_content', $where);
+
                        // Flip uids:
                        $defLanguageCount = array_flip($defLanguageCount);
                        // Traverse any selected elements and unset original UID if any:
-                       $rowArr = $this->getResult($result);
                        foreach ($rowArr as $row) {
+                               BackendUtility::workspaceOL('tt_content', $row);
                                unset($defLanguageCount[$row['l18n_parent']]);
                        }
                        // Flip again:
@@ -1465,24 +1582,66 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
         *
         * @param array $defLanguageCount Numeric array with uids of tt_content elements in the default language
         * @param int $lP Sys language UID
+        * @param int $colPos Column position
         * @return string "Copy languages" button, if available.
         */
-       public function newLanguageButton($defLanguageCount, $lP) {
-               if (!$this->doEdit || empty($defLanguageCount) || !$lP) {
+       public function newLanguageButton($defLanguageCount, $lP, $colPos = 0) {
+               if (!$this->doEdit || !$lP) {
                        return '';
                }
-               $params = '';
-               foreach ($defLanguageCount as $uidVal) {
-                       $params .= '&cmd[tt_content][' . $uidVal . '][localize]=' . $lP;
-               }
-               // Copy for language:
-               $onClick = 'window.location.href=' . GeneralUtility::quoteJSvalue($this->getPageLayoutController()->doc->issueCommand($params)) . '; return false;';
-               $theNewButton = '<div class="t3-page-lang-copyce">' .
-                       $this->getPageLayoutController()->doc->t3Button(
-                               $onClick,
-                               $this->getLanguageService()->getLL('newPageContent_copyForLang') . ' [' . count($defLanguageCount) . ']'
-                       ) . '</div>';
-               return $theNewButton;
+
+               $copyFromLanguageMenu = '';
+               foreach ($this->getLanguagesToCopyFrom(GeneralUtility::_GP('id'), $lP, $colPos) as $languageId => $label) {
+                       $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;
+                       }
+               }
+               if ($copyFromLanguageMenu !== '') {
+                       $copyFromLanguageMenu =
+                               '<ul class="dropdown-menu">'
+                                       . $copyFromLanguageMenu
+                               . '</ul>';
+               }
+
+               if (!empty($defLanguageCount)) {
+                       $params = '';
+                       foreach ($defLanguageCount as $uidVal) {
+                               $params .= '&cmd[tt_content][' . $uidVal . '][localize]=' . $lP;
+                       }
+
+                       // We have content in the default language, create a split button
+                       $onClick = 'window.location.href=' . GeneralUtility::quoteJSvalue($this->getPageLayoutController()->doc->issueCommand($params)) . '; return false;';
+                       $theNewButton =
+                               '<div class="btn-group">'
+                                       . $this->getPageLayoutController()->doc->t3Button(
+                                               $onClick,
+                                               $this->getLanguageService()->getLL('newPageContent_copyForLang', TRUE) . ' [' . count($defLanguageCount) . ']'
+                                       );
+                       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>'
+                                       . '</button>'
+                                       . $copyFromLanguageMenu;
+                       }
+                       $theNewButton .= '</div>';
+               } else {
+                       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">'
+                                       . $this->getLanguageService()->getLL('newPageContent_copyFromAnotherLang_button', TRUE) . ' <span class="caret"></span>'
+                                       . '</button>'
+                                       . $copyFromLanguageMenu
+                                       . '</div>';
+                       } else {
+                               $theNewButton = '';
+                       }
+               }
+
+               return '<div class="t3-page-lang-copyce">' . $theNewButton . '</div>';
        }
 
        /**
@@ -1528,6 +1687,165 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
        }
 
        /**
+        * Get available languages for a page
+        *
+        * @param int $pageId
+        * @return array
+        */
+       protected function getAvailableLanguages($pageId) {
+               // First, select all
+               $res = $this->getPageLayoutController()->exec_languageQuery(0);
+               $langSelItems = array();
+               while ($row = $this->getDatabase()->sql_fetch_assoc($res)) {
+                       if ($this->getBackendUser()->checkLanguageAccess($row['uid'])) {
+                               $langSelItems[$row['uid']] = $row['title'];
+                       }
+               }
+               $this->getDatabase()->sql_free_result($res);
+
+               // Remove disallowed languages
+               if (count($langSelItems) > 1
+                       && !$this->getBackendUser()->user['admin']
+                       && $this->getBackendUser()->groupData['allowed_languages'] !== ''
+               ) {
+                       $allowed_languages = array_flip(explode(',', $this->getBackendUser()->groupData['allowed_languages']));
+                       if (!empty($allowed_languages)) {
+                               foreach ($langSelItems as $key => $value) {
+                                       if (!isset($allowed_languages[$key]) && $key != 0) {
+                                               unset($langSelItems[$key]);
+                                       }
+                               }
+                       }
+               }
+               // Remove disabled languages
+               $modSharedTSconfig = BackendUtility::getModTSconfig($pageId, 'mod.SHARED');
+               $disableLanguages = isset($modSharedTSconfig['properties']['disableLanguages'])
+                       ? GeneralUtility::trimExplode(',', $modSharedTSconfig['properties']['disableLanguages'], TRUE)
+                       : array();
+               if (!empty($langSelItems) && !empty($disableLanguages)) {
+                       foreach ($disableLanguages as $language) {
+                               if ($language != 0 && isset($langSelItems[$language])) {
+                                       unset($langSelItems[$language]);
+                               }
+                       }
+               }
+
+               return $langSelItems;
+       }
+
+       /**
+        * Get available languages for copying into another language
+        *
+        * @param int $pageId
+        * @param int $excludeLanguage
+        * @param int $colPos
+        * @return array
+        */
+       protected function getLanguagesToCopyFrom($pageId, $excludeLanguage = NULL, $colPos = 0) {
+               $langSelItems = array();
+               if (!$this->isColumnEmpty($colPos, 0)) {
+                       $langSelItems[0] = $this->getLanguageService()->getLL('newPageContent_translateFromDefault', TRUE);
+               }
+
+               $languages = $this->getUsedLanguagesInPageAndColumn($pageId, $colPos);
+               foreach ($languages as $uid => $language) {
+                       $langSelItems[$uid] = sprintf($this->getLanguageService()->getLL('newPageContent_copyFromAnotherLang'), htmlspecialchars($language['title']));
+               }
+
+               if (isset($langSelItems[$excludeLanguage])) {
+                       unset($langSelItems[$excludeLanguage]);
+               }
+
+               return $langSelItems;
+       }
+
+       /**
+        * 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.
@@ -1589,13 +1907,13 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                ));
                                $onChangeContent = 'window.location.href=' . GeneralUtility::quoteJSvalue($url . '&overrideVals[pages_language_overlay][sys_language_uid]=') . '+this.options[this.selectedIndex].value';
                                return '<div class="form-inline form-inline-spaced">'
-                                       . '<div class="form-group">'
-                                       . '<label for="createNewLanguage">'
-                                       . $this->getLanguageService()->getLL('new_language', TRUE)
-                                       . '</label>'
-                                       . '<select class="form-control input-sm" name="createNewLanguage" onchange="' . htmlspecialchars($onChangeContent) . '">'
-                                       . implode('', $langSelItems)
-                                       . '</select></div></div>';
+                               . '<div class="form-group">'
+                               . '<label for="createNewLanguage">'
+                               . $this->getLanguageService()->getLL('new_language', TRUE)
+                               . '</label>'
+                               . '<select class="form-control input-sm" name="createNewLanguage" onchange="' . htmlspecialchars($onChangeContent) . '">'
+                               . implode('', $langSelItems)
+                               . '</select></div></div>';
                        }
                }
                return '';
@@ -1729,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)) {
@@ -1783,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>';
        }
 
        /**
@@ -1811,7 +2127,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                // Traverse table names and set them in allowedTableNames array IF they can be read-accessed by the user.
                if (is_array($tableNames)) {
                        foreach ($tableNames as $k => $v) {
-                               if ($this->getBackendUser()->check('tables_select', $k)) {
+                               if (!$GLOBALS['TCA'][$k]['ctrl']['hideTable'] && $this->getBackendUser()->check('tables_select', $k)) {
                                        $allowedTableNames['table_' . $k] = $k;
                                }
                        }
@@ -1858,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);
                                }
                        }
                }
@@ -1895,7 +2209,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
         * @return string HTML for thumbnails, if any.
         */
        public function getThumbCodeUnlinked($row, $table, $field) {
-               return BackendUtility::thumbCode($row, $table, $field, $this->backPath, '', NULL, 0, '', '', FALSE);
+               return BackendUtility::thumbCode($row, $table, $field, '', '', NULL, 0, '', '', FALSE);
        }
 
        /**