Commit fb2fb5c4 authored by Jo Hasenau's avatar Jo Hasenau Committed by Christian Kuhn
Browse files

[FEATURE] Collect lost elements and show them separately from backend layout

Resolves: #67884
Releases: master
Change-Id: I7c14886e5dc1c81d7d816e5f2eb5d36afb8cdbf9
Reviewed-on: https://review.typo3.org/53040


Tested-by: default avatarTYPO3com <no-reply@typo3.com>
Reviewed-by: Mona Muzaffar's avatarMona Muzaffar <mona.muzaffar@gmx.de>
Tested-by: Mona Muzaffar's avatarMona Muzaffar <mona.muzaffar@gmx.de>
Tested-by: Riccardo De Contardi's avatarRiccardo De Contardi <erredeco@gmail.com>
Tested-by: default avatarJasmina Ließmann <code@frauliessmann.de>
Reviewed-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
parent 6189219a
......@@ -21,6 +21,10 @@ $page-ce-header-bg-danger: $brand-danger;
$page-ce-header-hover-bg-danger: darken($brand-danger, 10%);
$page-ce-header-border-danger: $page-ce-header-bg-danger;
$page-ce-header-hover-border-danger: $page-ce-header-hover-bg-danger;
$page-ce-header-bg-warning: $brand-warning;
$page-ce-header-hover-bg-warning: darken($brand-warning, 10%);
$page-ce-header-border-warning: $page-ce-header-bg-warning;
$page-ce-header-hover-border-warning: $page-ce-header-hover-bg-warning;
$page-ce-dropzone-bg: $state-success-bg;
$page-ce-dropzone-border: $state-success-border;
$page-ce-dropzone-border-radius: $page-ce-border-radius;
......@@ -87,6 +91,11 @@ $page-ce-dropzone-possible-border: $state-warning-border;
color: $page-column-header-color;
text-align: left;
[data-colpos='unused'] & {
color: $state-warning-text;
padding-top: $grid-gutter-width*2;
}
a {
position: relative;
}
......@@ -139,11 +148,11 @@ $page-ce-dropzone-possible-border: $state-warning-border;
.t3-page-ce-body-inner {
padding: $page-grid-spacing;
word-wrap: break-word;
}
.t3-page-ce-body-inner img {
max-width: 100%;
height: auto;
img {
max-width: 100%;
height: auto;
}
}
.t3-page-ce-header {
......@@ -237,6 +246,33 @@ $page-ce-dropzone-possible-border: $state-warning-border;
}
}
.t3-page-ce-warning {
&:hover {
.t3-page-ce-header {
background-color: $page-ce-header-hover-bg-warning;
border-color: $page-ce-header-hover-border-warning;
}
.t3-page-ce-body {
border-color: $page-ce-header-hover-border-warning;
}
}
.t3-page-ce-header {
background-color: $page-ce-header-bg-warning;
border-color: $page-ce-header-border-warning;
&:hover {
background-color: $page-ce-header-hover-bg-warning;
border-color: $page-ce-header-hover-border-warning;
}
}
.t3-page-ce-body {
border-color: $page-ce-header-border-warning;
}
}
.t3-page-ce-hidden {
opacity: $page-ce-hidden-opacity;
......
......@@ -524,12 +524,14 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
} else {
$showLanguage = $expressionBuilder->eq('sys_language_uid', $lP);
}
$cList = explode(',', $this->tt_contentConfig['cols']);
$content = [];
$head = [];
$backendLayout = $this->getBackendLayoutView()->getSelectedBackendLayout($this->id);
$columns = $backendLayout['__colPosList'];
// Select content records per column
$contentRecordsPerColumn = $this->getContentRecordsPerColumn('table', $id, array_values($cList), $showLanguage);
$contentRecordsPerColumn = $this->getContentRecordsPerColumn('table', $id, $columns, $showLanguage);
$cList = array_keys($contentRecordsPerColumn);
// For each column, render the content into a variable:
foreach ($cList as $columnId) {
if (!isset($this->contentElementCache[$lP][$columnId])) {
......@@ -587,7 +589,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
. ' '
. htmlspecialchars($this->getLanguageService()->getLL('content')) . '</a>';
}
if ($this->getBackendUser()->checkLanguageAccess($lP)) {
if ($this->getBackendUser()->checkLanguageAccess($lP) && $columnId !== 'unused') {
$content[$columnId] .= '
<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-' . $columnId . '-' . 'page-' . $id . '-' . StringUtility::getUniqueId() . '">'
......@@ -616,7 +618,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
$this->contentElementCache[$lP][$columnId][$row['uid']] = $row;
if ($this->tt_contentConfig['languageMode']) {
$languageColumn[$columnId][$lP] = $head[$columnId] . $content[$columnId];
if (!$this->defLangBinding) {
if (!$this->defLangBinding && $columnId !== 'unused') {
$languageColumn[$columnId][$lP] .= $this->newLanguageButton(
$this->getNonTranslatedTTcontentUids($defaultLanguageElementsByColumn[$columnId], $id, $lP),
$lP,
......@@ -648,11 +650,13 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
$isDisabled = $this->isDisabled('tt_content', $row);
$statusHidden = $isDisabled ? ' t3-page-ce-hidden t3js-hidden-record' : '';
$displayNone = !$this->tt_contentConfig['showHidden'] && $isDisabled ? ' style="display: none;"' : '';
$highlightHeader = false;
$highlightHeader = '';
if ($this->checkIfTranslationsExistInLanguage([], (int)$row['sys_language_uid']) && (int)$row['l18n_parent'] === 0) {
$highlightHeader = true;
$highlightHeader = ' t3-page-ce-danger';
} elseif ($columnId === 'unused') {
$highlightHeader = ' t3-page-ce-warning';
}
$singleElementHTML = '<div class="t3-page-ce ' . ($highlightHeader ? 't3-page-ce-danger' : '') . ' t3js-page-ce t3js-page-ce-sortable ' . $statusHidden . '" id="element-tt_content-'
$singleElementHTML = '<div class="t3-page-ce' . $highlightHeader . ' t3js-page-ce t3js-page-ce-sortable ' . $statusHidden . '" id="element-tt_content-'
. $row['uid'] . '" data-table="tt_content" data-uid="' . $row['uid'] . '"' . $displayNone . '>' . $singleElementHTML . '</div>';
if ($this->tt_contentConfig['languageMode']) {
......@@ -665,6 +669,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
&& $this->getPageLayoutController()->contentIsNotLockedForEditors()
&& $this->getBackendUser()->checkLanguageAccess($lP)
&& (!$this->checkIfTranslationsExistInLanguage($contentRecordsPerColumn, $lP))
&& $columnId !== 'unused'
) {
// New content element:
if ($this->option_newWizard) {
......@@ -717,9 +722,25 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
$colTitle = $this->getLanguageService()->sL($item[0]);
}
}
$editParam = $this->doEdit && !empty($rowArr)
? '&edit[tt_content][' . $editUidList . ']=edit' . $pageTitleParamForAltDoc
: '';
if ($columnId === 'unused') {
if (empty($unusedElementsMessage)) {
$unusedElementsMessage = GeneralUtility::makeInstance(
FlashMessage::class,
$this->getLanguageService()->getLL('staleUnusedElementsWarning'),
$this->getLanguageService()->getLL('staleUnusedElementsWarningTitle'),
FlashMessage::WARNING
);
$service = GeneralUtility::makeInstance(FlashMessageService::class);
$queue = $service->getMessageQueueByIdentifier();
$queue->addMessage($unusedElementsMessage);
}
$colTitle = $this->getLanguageService()->sL('LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:colPos.I.unused');
$editParam = '';
} else {
$editParam = $this->doEdit && !empty($rowArr)
? '&edit[tt_content][' . $editUidList . ']=edit' . $pageTitleParamForAltDoc
: '';
}
$head[$columnId] .= $this->tt_content_drawColHeader($colTitle, $editParam);
}
}
......@@ -729,9 +750,9 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
// in language mode process the content elements, but only fill $languageColumn. output will be generated later
$sortedLanguageColumn = [];
foreach ($cList as $columnId) {
if (GeneralUtility::inList($this->tt_contentConfig['activeCols'], $columnId)) {
if (GeneralUtility::inList($this->tt_contentConfig['activeCols'], $columnId) || $columnId === 'unused') {
$languageColumn[$columnId][$lP] = $head[$columnId] . $content[$columnId];
if (!$this->defLangBinding) {
if (!$this->defLangBinding && $columnId !== 'unused') {
$languageColumn[$columnId][$lP] .= $this->newLanguageButton(
$this->getNonTranslatedTTcontentUids($defaultLanguageElementsByColumn[$columnId], $id, $lP),
$lP,
......@@ -742,9 +763,11 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
$sortedLanguageColumn[$columnId] = $languageColumn[$columnId];
}
}
if (!empty($languageColumn['unused'])) {
$sortedLanguageColumn['unused'] = $languageColumn['unused'];
}
$languageColumn = $sortedLanguageColumn;
} else {
$backendLayout = $this->getBackendLayoutView()->getSelectedBackendLayout($this->id);
// GRID VIEW:
$grid = '<div class="t3-grid-container"><table border="0" cellspacing="0" cellpadding="0" width="100%" class="t3-page-columns t3-grid-table t3js-page-columns">';
// Add colgroups
......@@ -807,6 +830,23 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
}
$grid .= '</tr>';
}
if (!empty($content['unused'])) {
$grid .= '<tr>';
// Which tt_content colPos should be displayed inside this cell
$columnKey = 'unused';
// Render the grid cell
$colSpan = (int)$backendLayout['__config']['backend_layout.']['colCount'];
$grid .= '<td valign="top"' .
($colSpan > 0 ? ' colspan="' . $colSpan . '"' : '') .
($rowSpan > 0 ? ' rowspan="' . $rowSpan . '"' : '') .
' data-colpos="unused" data-language-uid="' . $lP . '" class="t3js-page-lang-column-' . $lP . ' t3js-page-column t3-grid-cell t3-page-column t3-page-column-' . $columnKey .
($colSpan > 0 ? ' t3-gridCell-width' . $colSpan : '') . '">';
// Draw the pre-generated header with edit and new buttons if a colPos is assigned.
// If not, a new header without any buttons will be generated.
$grid .= $head[$columnKey] . $content[$columnKey];
$grid .= '</td></tr>';
}
$out .= $grid . '</table></div>';
}
// CSH:
......@@ -957,7 +997,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
foreach ($languageColumn as $cKey => $cCont) {
$out .= '<tr>';
foreach ($cCont as $languageId => $columnContent) {
$out .= '<td valign="top" class="t3-grid-cell t3-page-column t3js-page-column t3js-page-lang-column t3js-page-lang-column-' . $languageId . '">' . $columnContent . '</td>';
$out .= '<td valign="top" data-colpos="' . $cKey . '" class="t3-grid-cell t3-page-column t3js-page-column t3js-page-lang-column t3js-page-lang-column-' . $languageId . '">' . $columnContent . '</td>';
}
$out .= '</tr>';
if ($this->defLangBinding) {
......@@ -1195,30 +1235,30 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
*/
protected function getContentRecordsPerColumn($table, $id, array $columns, $additionalWhereClause = '')
{
$columns = array_map('intval', $columns);
$contentRecordsPerColumn = array_fill_keys($columns, []);
$expressionBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
->getQueryBuilderForTable('tt_content')
->expr();
$columns = array_flip($columns);
$queryBuilder = $this->getQueryBuilder(
'tt_content',
$id,
[
$expressionBuilder->in('colPos', $columns),
$additionalWhereClause
]
);
// Traverse any selected elements and render their display code:
$results = $this->getResult($queryBuilder->execute());
$unused = [];
foreach ($results as $record) {
$columnValue = $record['colPos'];
$contentRecordsPerColumn[$columnValue][] = $record;
if (isset($columns[$record['colPos']])) {
$columnValue = (string)$record['colPos'];
$contentRecordsPerColumn[$columnValue][] = $record;
} else {
$unused[] = $record;
}
}
if (!empty($unused)) {
$contentRecordsPerColumn['unused'] = $unused;
}
return $contentRecordsPerColumn;
}
......
......@@ -315,6 +315,12 @@
<trans-unit id="staleTranslationWarningTitle">
<source>Inconsistent content detected in language "%s"</source>
</trans-unit>
<trans-unit id="staleUnusedElementsWarning">
<source>These elements don't belong to any of the available columns of this page. You should either delete them or move them to existing columns. We highlighted the problematic records for you.</source>
</trans-unit>
<trans-unit id="staleUnusedElementsWarningTitle">
<source>Unused elements detected on this page</source>
</trans-unit>
<trans-unit id="localize.chooseLanguage">
<source>Choose your language</source>
</trans-unit>
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -243,9 +243,7 @@ define(['jquery', 'jquery-ui/droppable'], function ($) {
.insertAfter($droppableElement.closest(DragDrop.contentIdentifier));
}
}
if ($('.t3js-page-lang-column').length || $copyAction || $pasteAction) {
self.location.reload(true);
}
self.location.reload(true);
}
});
});
......
......@@ -135,6 +135,9 @@
<trans-unit id="colPos.I.3">
<source>Border</source>
</trans-unit>
<trans-unit id="colPos.I.unused">
<source>Unused</source>
</trans-unit>
<trans-unit id="date">
<source>Date</source>
</trans-unit>
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment