[TASK] Use GeneralUtility::quoteJSvalue() where needed part 3
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Classes / Controller / TranslationStatusController.php
1 <?php
2 namespace TYPO3\CMS\Frontend\Controller;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Backend\Tree\View\PageTreeView;
18 use TYPO3\CMS\Backend\Utility\BackendUtility;
19 use TYPO3\CMS\Backend\Utility\IconUtility;
20 use TYPO3\CMS\Core\Utility\GeneralUtility;
21
22 /**
23 * Class for displaying translation status of pages in the tree.
24 *
25 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
26 */
27 class TranslationStatusController extends \TYPO3\CMS\Backend\Module\AbstractFunctionModule {
28
29 /**
30 * Returns the menu array
31 *
32 * @return array
33 */
34 public function modMenu() {
35 $lang = $this->getLanguageService();
36 $menuArray = array(
37 'depth' => array(
38 0 => $lang->getLL('depth_0'),
39 1 => $lang->getLL('depth_1'),
40 2 => $lang->getLL('depth_2'),
41 3 => $lang->getLL('depth_3'),
42 999 => $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_infi')
43 )
44 );
45 // Languages:
46 $lang = $this->getSystemLanguages();
47 $menuArray['lang'] = array(
48 0 => '[All]'
49 );
50 foreach ($lang as $langRec) {
51 $menuArray['lang'][$langRec['uid']] = $langRec['title'];
52 }
53 return $menuArray;
54 }
55
56 /**
57 * MAIN function for page information of localization
58 *
59 * @return string Output HTML for the module.
60 */
61 public function main() {
62 $theOutput = $this->pObj->doc->header($this->getLanguageService()->sL('LLL:EXT:cms/web_info/locallang.xlf:lang_title'));
63 if ($this->pObj->id) {
64 // Depth selector:
65 $h_func = BackendUtility::getFuncMenu($this->pObj->id, 'SET[depth]', $this->pObj->MOD_SETTINGS['depth'], $this->pObj->MOD_MENU['depth']);
66 $h_func .= BackendUtility::getFuncMenu($this->pObj->id, 'SET[lang]', $this->pObj->MOD_SETTINGS['lang'], $this->pObj->MOD_MENU['lang']);
67 $theOutput .= $h_func;
68 // Add CSH:
69 $theOutput .= BackendUtility::cshItem('_MOD_web_info', 'lang', NULL, '|<br />');
70 // Showing the tree:
71 // Initialize starting point of page tree:
72 $treeStartingPoint = (int)$this->pObj->id;
73 $treeStartingRecord = BackendUtility::getRecordWSOL('pages', $treeStartingPoint);
74 $depth = $this->pObj->MOD_SETTINGS['depth'];
75 // Initialize tree object:
76 $tree = GeneralUtility::makeInstance(PageTreeView::class);
77 $tree->init('AND ' . $this->getBackendUser()->getPagePermsClause(1));
78 $tree->addField('l18n_cfg');
79 // Creating top icon; the current page
80 $HTML = IconUtility::getSpriteIconForRecord('pages', $treeStartingRecord);
81 $tree->tree[] = array(
82 'row' => $treeStartingRecord,
83 'HTML' => $HTML
84 );
85 // Create the tree from starting point:
86 if ($depth) {
87 $tree->getTree($treeStartingPoint, $depth, '');
88 }
89 // Render information table:
90 $theOutput .= $this->renderL10nTable($tree);
91 }
92 return $theOutput;
93 }
94
95 /**
96 * Rendering the localization information table.
97 *
98 * @param array $tree The Page tree data
99 * @return string HTML for the localization information table.
100 */
101 public function renderL10nTable(&$tree) {
102 $lang = $this->getLanguageService();
103 // System languages retrieved:
104 $languages = $this->getSystemLanguages();
105 // Title length:
106 $titleLen = $this->getBackendUser()->uc['titleLen'];
107 // Put together the TREE:
108 $output = '';
109 $newOL_js = array();
110 $langRecUids = array();
111 foreach ($tree->tree as $data) {
112 $tCells = array();
113 $langRecUids[0][] = $data['row']['uid'];
114 // Page icons / titles etc.
115 $tCells[] = '<td' . ($data['row']['_CSSCLASS'] ? ' class="' . $data['row']['_CSSCLASS'] . '"' : '') . '>' .
116 $GLOBALS['SOBE']->doc->wrapClickMenuOnIcon($data['HTML'], 'pages', $data['row']['uid']) .
117 '<a href="#" onclick="' . htmlspecialchars(
118 'top.loadEditId(' . (int)$data['row']['uid'] . ',"&SET[language]=0"); return false;'
119 ) . '" title="' . $lang->sL('LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_editPage') . '">' .
120 htmlspecialchars(GeneralUtility::fixed_lgd_cs($data['row']['title'], $titleLen)) .
121 '</a>' .
122 ((string)$data['row']['nav_title'] !== '' ? ' [Nav: <em>' . htmlspecialchars(GeneralUtility::fixed_lgd_cs($data['row']['nav_title'], $titleLen)) . '</em>]' : '') .
123 '</td>';
124 // DEFAULT language:
125 // "View page" link is created:
126 $viewPageLink = '<a href="#" onclick="' . htmlspecialchars(BackendUtility::viewOnClick(
127 $data['row']['uid'], $GLOBALS['BACK_PATH'], '', '', '', '&L=###LANG_UID###')
128 ) . '" title="' . $lang->sL('LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_viewPage') . '">' .
129 IconUtility::getSpriteIcon('actions-document-view') . '</a>';
130 $status = $data['row']['l18n_cfg'] & 1 ? 'danger' : 'success';
131 // Create links:
132 $info = '';
133 $editUid = $data['row']['uid'];
134 $params = '&edit[pages][' . $editUid . ']=edit';
135 $info .= '<a href="#" onclick="' . htmlspecialchars(BackendUtility::editOnClick($params))
136 . '" title="' . $lang->sL(
137 'LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_editDefaultLanguagePage'
138 ) . '">' . IconUtility::getSpriteIcon('actions-document-open') . '</a>';
139 $info .= str_replace('###LANG_UID###', '0', $viewPageLink);
140 $info .= '&nbsp;';
141 $info .= $data['row']['l18n_cfg'] & 1 ? '<span title="' . $lang->sL('LLL:EXT:cms/locallang_tca.xlf:pages.l18n_cfg.I.1', TRUE) . '">D</span>' : '&nbsp;';
142 $info .= GeneralUtility::hideIfNotTranslated($data['row']['l18n_cfg']) ? '<span title="' . $lang->sL('LLL:EXT:cms/locallang_tca.xlf:pages.l18n_cfg.I.2', TRUE) . '">N</span>' : '&nbsp;';
143 // Put into cell:
144 $tCells[] = '<td class="' . $status . ' col-border-left">' . $info . '</td>';
145 $tCells[] = '<td class="' . $status . '" title="' . $lang->sL(
146 'LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_CEcount'
147 ) . '" align="center">' . $this->getContentElementCount($data['row']['uid'], 0) . '</td>';
148 $modSharedTSconfig = BackendUtility::getModTSconfig($data['row']['uid'], 'mod.SHARED');
149 $disableLanguages = isset($modSharedTSconfig['properties']['disableLanguages']) ? GeneralUtility::trimExplode(',', $modSharedTSconfig['properties']['disableLanguages'], TRUE) : array();
150 // Traverse system languages:
151 foreach ($languages as $langRow) {
152 if ($this->pObj->MOD_SETTINGS['lang'] == 0 || (int)$this->pObj->MOD_SETTINGS['lang'] === (int)$langRow['uid']) {
153 $row = $this->getLangStatus($data['row']['uid'], $langRow['uid']);
154 $info = '';
155 if (is_array($row)) {
156 $langRecUids[$langRow['uid']][] = $row['uid'];
157 $status = $row['_HIDDEN'] ? (GeneralUtility::hideIfNotTranslated($data['row']['l18n_cfg']) || $data['row']['l18n_cfg'] & 1 ? 'danger' : '') : 'success';
158 $icon = IconUtility::getSpriteIconForRecord(
159 'pages_language_overlay',
160 $row,
161 array('class' => 'c-recIcon')
162 );
163 $info = $icon . htmlspecialchars(
164 GeneralUtility::fixed_lgd_cs($row['title'], $titleLen)
165 ) . ((string)$row['nav_title'] !== '' ? ' [Nav: <em>' . htmlspecialchars(
166 GeneralUtility::fixed_lgd_cs($row['nav_title'], $titleLen)
167 ) . '</em>]' : '') . ($row['_COUNT'] > 1 ? '<div>' . $lang->sL(
168 'LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_badThingThereAre'
169 ) . '</div>' : '');
170 $tCells[] = '<td class="' . $status . ' col-border-left">' .
171 '<a href="#" onclick="' . htmlspecialchars(
172 'top.loadEditId(' . (int)$data['row']['uid'] . ',"&SET[language]=' . $langRow['uid'] . '"); return false;'
173 ) . '" title="' . $lang->sL(
174 'LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_editPageLang'
175 ) . '">' . $info . '</a></td>';
176 // Edit whole record:
177 $info = '';
178 $editUid = $row['uid'];
179 $params = '&edit[pages_language_overlay][' . $editUid . ']=edit';
180 $info .= '<a href="#" onclick="' . htmlspecialchars(BackendUtility::editOnClick($params))
181 . '" title="' . $lang->sL(
182 'LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_editLanguageOverlayRecord'
183 ) . '">' . IconUtility::getSpriteIcon('actions-document-open') . '</a>';
184 $info .= str_replace('###LANG_UID###', $langRow['uid'], $viewPageLink);
185 $tCells[] = '<td class="' . $status . '">' . $info . '</td>';
186 $tCells[] = '<td class="' . $status . '" title="' . $lang->sL(
187 'LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_CEcount'
188 ) . '" align="center">' . $this->getContentElementCount($data['row']['uid'], $langRow['uid']) . '</td>';
189 } else {
190 if (in_array($langRow['uid'], $disableLanguages)) {
191 // Language has been disabled for this page
192 $status = 'danger';
193 $info = '';
194 } else {
195 $status = GeneralUtility::hideIfNotTranslated($data['row']['l18n_cfg']) || $data['row']['l18n_cfg'] & 1 ? 'danger' : '';
196 $info = '<input type="checkbox" name="newOL[' . $langRow['uid'] . '][' . $data['row']['uid'] . ']" value="1" />';
197 $newOL_js[$langRow['uid']] .= '
198 +(document.webinfoForm['
199 . GeneralUtility::quoteJSvalue('newOL[' . $langRow['uid'] . '][' . $data['row']['uid'] . ']')
200 . '].checked ? '
201 . GeneralUtility::quoteJSvalue('&edit[pages_language_overlay][' . $data['row']['uid'] . ']=new')
202 . ' : \'\')
203 ';
204 }
205 $tCells[] = '<td class="' . $status . ' col-border-left">&nbsp;</td>';
206 $tCells[] = '<td class="' . $status . '">&nbsp;</td>';
207 $tCells[] = '<td class="' . $status . '">' . $info . '</td>';
208 }
209 }
210 }
211 $output .= '
212 <tr>
213 ' . implode('
214 ', $tCells) . '
215 </tr>';
216 }
217 // Put together HEADER:
218 $tCells = array();
219 $tCells[] = '<td>' . $lang->sL('LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_page') . ':</td>';
220 if (is_array($langRecUids[0])) {
221 $params = '&edit[pages][' . implode(',', $langRecUids[0]) . ']=edit&columnsOnly=title,nav_title,l18n_cfg,hidden';
222 $editIco = '<a href="#" onclick="' . htmlspecialchars(BackendUtility::editOnClick($params))
223 . '" title="' . $lang->sL(
224 'LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_editPageProperties'
225 ) . '">' . IconUtility::getSpriteIcon('actions-document-new') . '</a>';
226 } else {
227 $editIco = '';
228 }
229 $tCells[] = '<td class="col-border-left" colspan="2">' . $lang->sL(
230 'LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_default'
231 ) . ':' . $editIco . '</td>';
232 foreach ($languages as $langRow) {
233 if ($this->pObj->MOD_SETTINGS['lang'] == 0 || (int)$this->pObj->MOD_SETTINGS['lang'] === (int)$langRow['uid']) {
234 // Title:
235 $tCells[] = '<td class="col-border-left">' . htmlspecialchars($langRow['title']) . '</td>';
236 // Edit language overlay records:
237 if (is_array($langRecUids[$langRow['uid']])) {
238 $params = '&edit[pages_language_overlay][' .
239 implode(',', $langRecUids[$langRow['uid']]) .
240 ']=edit&columnsOnly=title,nav_title,hidden';
241 $tCells[] = '<td><a href="#" onclick="' . htmlspecialchars(BackendUtility::editOnClick($params))
242 . '" title="' . $lang->sL(
243 'LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_editLangOverlays'
244 ) . '">' . IconUtility::getSpriteIcon('actions-document-open') . '</a></td>';
245 } else {
246 $tCells[] = '<td>&nbsp;</td>';
247 }
248 // Create new overlay records:
249 $params = '\'' .
250 $newOL_js[$langRow['uid']] .
251 '+\'&columnsOnly=title,hidden,sys_language_uid&defVals[pages_language_overlay][sys_language_uid]=' .
252 $langRow['uid'];
253 $tCells[] = '<td><a href="#" onclick="' . htmlspecialchars(BackendUtility::editOnClick($params))
254 . '" title="' . $lang->sL(
255 'LLL:EXT:cms/web_info/locallang.xlf:lang_getlangsta_createNewTranslationHeaders'
256 ) . '">' . IconUtility::getSpriteIcon('actions-document-new') . '</a></td>';
257 }
258 }
259
260 $output =
261 '<div class="table-fit">' .
262 '<table class="table table-striped table-hover" id="langTable">' .
263 '<thead>' .
264 '<tr>' .
265 implode('', $tCells) .
266 '</tr>' .
267 '</thead>' .
268 '<tbody>' .
269 $output .
270 '</tbody>' .
271 '</table>' .
272 '</div>';
273 return $output;
274 }
275
276 /**
277 * Selects all system languages (from sys_language)
278 *
279 * @return array System language records in an array.
280 */
281 public function getSystemLanguages() {
282 if (!$this->getBackendUser()->user['admin'] && $this->getBackendUser()->groupData['allowed_languages'] !== '') {
283 $allowed_languages = array_flip(explode(',', $this->getBackendUser()->groupData['allowed_languages']));
284 }
285 $res = $this->getDatabaseConnection()->exec_SELECTquery('*', 'sys_language', '1=1' . BackendUtility::deleteClause('sys_language'));
286 $outputArray = array();
287 while ($row = $this->getDatabaseConnection()->sql_fetch_assoc($res)) {
288 if (is_array($allowed_languages) && count($allowed_languages)) {
289 if (isset($allowed_languages[$row['uid']])) {
290 $outputArray[] = $row;
291 }
292 } else {
293 $outputArray[] = $row;
294 }
295 }
296 $this->getDatabaseConnection()->sql_free_result($res);
297 return $outputArray;
298 }
299
300 /**
301 * Get an alternative language record for a specific page / language
302 *
303 * @param int $pageId Page ID to look up for.
304 * @param int $langId Language UID to select for.
305 * @return array pages_languages_overlay record
306 */
307 public function getLangStatus($pageId, $langId) {
308 $res = $this->getDatabaseConnection()->exec_SELECTquery(
309 '*',
310 'pages_language_overlay',
311 'pid=' . (int)$pageId .
312 ' AND sys_language_uid=' . (int)$langId .
313 BackendUtility::deleteClause('pages_language_overlay') .
314 BackendUtility::versioningPlaceholderClause('pages_language_overlay')
315 );
316 $row = $this->getDatabaseConnection()->sql_fetch_assoc($res);
317 BackendUtility::workspaceOL('pages_language_overlay', $row);
318 if (is_array($row)) {
319 $row['_COUNT'] = $this->getDatabaseConnection()->sql_num_rows($res);
320 $row['_HIDDEN'] = $row['hidden'] || (int)$row['endtime'] > 0 && (int)$row['endtime'] < $GLOBALS['EXEC_TIME'] || $GLOBALS['EXEC_TIME'] < (int)$row['starttime'];
321 }
322 return $row;
323 }
324
325 /**
326 * Counting content elements for a single language on a page.
327 *
328 * @param int $pageId Page id to select for.
329 * @param int $sysLang Sys language uid
330 * @return int Number of content elements from the PID where the language is set to a certain value.
331 */
332 public function getContentElementCount($pageId, $sysLang) {
333 $count = $this->getDatabaseConnection()->exec_SELECTcountRows('uid', 'tt_content', 'pid=' . (int)$pageId . ' AND sys_language_uid=' . (int)$sysLang . BackendUtility::deleteClause('tt_content') . BackendUtility::versioningPlaceholderClause('tt_content'));
334 return $count ?: '-';
335 }
336
337 /**
338 * Returns LanguageService
339 *
340 * @return \TYPO3\CMS\Lang\LanguageService
341 */
342 protected function getLanguageService() {
343 return $GLOBALS['LANG'];
344 }
345
346 /**
347 * Returns the database connection
348 *
349 * @return \TYPO3\CMS\Core\Database\DatabaseConnection
350 */
351 protected function getDatabaseConnection() {
352 return $GLOBALS['TYPO3_DB'];
353 }
354
355 /**
356 * Returns the current BE user.
357 *
358 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
359 */
360 protected function getBackendUser() {
361 return $GLOBALS['BE_USER'];
362 }
363
364 }