6f788f9f5b208046c552f536e87e675ebb6cbe84
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / RecordList / AbstractRecordList.php
1 <?php
2 namespace TYPO3\CMS\Backend\RecordList;
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\Configuration\TranslationConfigurationProvider;
18 use TYPO3\CMS\Backend\Routing\Router;
19 use TYPO3\CMS\Backend\Routing\UriBuilder;
20 use TYPO3\CMS\Backend\Utility\BackendUtility;
21 use TYPO3\CMS\Core\Database\DatabaseConnection;
22 use TYPO3\CMS\Core\Imaging\Icon;
23 use TYPO3\CMS\Core\Imaging\IconFactory;
24 use TYPO3\CMS\Core\Utility\GeneralUtility;
25 use TYPO3\CMS\Lang\LanguageService;
26
27 /**
28 * Library with a single function addElement that returns table
29 * rows based on some input.
30 *
31 * Base for class listing of database records and files in the
32 * modules Web>List and File>Filelist
33 */
34 abstract class AbstractRecordList
35 {
36 /**
37 * @var int
38 */
39 protected $id = 0;
40
41 /**
42 * default Max items shown
43 *
44 * @var int
45 */
46 public $iLimit = 10;
47
48 /**
49 * OBSOLETE - NOT USED ANYMORE. leftMargin
50 *
51 * @var int
52 */
53 public $leftMargin = 0;
54
55 /**
56 * @var int
57 */
58 public $showIcon = 1;
59
60 /**
61 * @var int
62 */
63 public $no_noWrap = 0;
64
65 /**
66 * If set this is <td> CSS-classname for odd columns in addElement. Used with db_layout / pages section
67 *
68 * @var string
69 */
70 public $oddColumnsCssClass = '';
71
72 /**
73 * Decides the columns shown. Filled with values that refers to the keys of the data-array. $this->fieldArray[0] is the title column.
74 *
75 * @var array
76 */
77 public $fieldArray = array();
78
79 /**
80 * Keys are fieldnames and values are td-parameters to add in addElement(), please use $addElement_tdCSSClass for CSS-classes;
81 *
82 * @var array
83 */
84 public $addElement_tdParams = array();
85
86 /**
87 * Keys are fieldnames and values are td-css-classes to add in addElement();
88 *
89 * @var array
90 */
91 public $addElement_tdCssClass = array();
92
93 /**
94 * Not used in this class - but maybe extension classes...
95 * Max length of strings
96 *
97 * @var int
98 */
99 public $fixedL = 30;
100
101 /**
102 * Script URL
103 *
104 * @var string
105 */
106 public $thisScript = '';
107
108 /**
109 * Set to zero, if you don't want a left-margin with addElement function
110 *
111 * @var int
112 */
113 public $setLMargin = 1;
114
115 /**
116 * Counter increased for each element. Used to index elements for the JavaScript-code that transfers to the clipboard
117 *
118 * @var int
119 */
120 public $counter = 0;
121
122 /**
123 * This could be set to the total number of items. Used by the fwd_rew_navigation...
124 *
125 * @var string
126 */
127 public $totalItems = '';
128
129 /**
130 * Internal (used in this class.)
131 *
132 * @var int
133 */
134 public $firstElementNumber = 0;
135
136 /**
137 * @var int
138 */
139 public $eCounter = 0;
140
141 /**
142 * String with accumulated HTML content
143 *
144 * @var string
145 */
146 public $HTMLcode = '';
147
148 /**
149 * Contains page translation languages
150 *
151 * @var array
152 */
153 public $pageOverlays = array();
154
155 /**
156 * Contains sys language icons and titles
157 *
158 * @var array
159 */
160 public $languageIconTitles = array();
161
162 /**
163 * @var TranslationConfigurationProvider
164 */
165 public $translateTools;
166
167 /**
168 * @var IconFactory
169 */
170 protected $iconFactory;
171
172 /**
173 * Constructor
174 */
175 public function __construct()
176 {
177 if (isset($GLOBALS['BE_USER']->uc['titleLen']) && $GLOBALS['BE_USER']->uc['titleLen'] > 0) {
178 $this->fixedL = $GLOBALS['BE_USER']->uc['titleLen'];
179 }
180 $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
181 $this->getTranslateTools();
182 $this->determineScriptUrl();
183 }
184
185 /**
186 * Sets the script url depending on being a module or script request
187 */
188 protected function determineScriptUrl()
189 {
190 if ($routePath = GeneralUtility::_GP('route')) {
191 $router = GeneralUtility::makeInstance(Router::class);
192 $route = $router->match($routePath);
193 $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
194 $this->thisScript = (string)$uriBuilder->buildUriFromRoute($route->getOption('_identifier'));
195 } elseif ($moduleName = GeneralUtility::_GP('M')) {
196 $this->thisScript = BackendUtility::getModuleUrl($moduleName);
197 } else {
198 $this->thisScript = GeneralUtility::getIndpEnv('SCRIPT_NAME');
199 }
200 }
201
202 /**
203 * @return string
204 */
205 protected function getThisScript()
206 {
207 return strpos($this->thisScript, '?') === false ? $this->thisScript . '?' : $this->thisScript . '&';
208 }
209
210 /**
211 * Returns a table-row with the content from the fields in the input data array.
212 * OBS: $this->fieldArray MUST be set! (represents the list of fields to display)
213 *
214 * @param int $h Is an integer >=0 and denotes how tall an element is. Set to '0' makes a halv line, -1 = full line, set to 1 makes a 'join' and above makes 'line'
215 * @param string $icon Is the <img>+<a> of the record. If not supplied the first 'join'-icon will be a 'line' instead
216 * @param array $data Is the dataarray, record with the fields. Notice: These fields are (currently) NOT htmlspecialchar'ed before being wrapped in <td>-tags
217 * @param string $rowParams Is insert in the <tr>-tags. Must carry a ' ' as first character
218 * @param string $_ OBSOLETE - NOT USED ANYMORE. $lMargin is the leftMargin (int)
219 * @param string $_ OBSOLETE - NOT USED ANYMORE. Is the HTML <img>-tag for an alternative 'gfx/ol/line.gif'-icon (used in the top)
220 * @param string $colType Defines the tag being used for the columns. Default is td.
221 * @return string HTML content for the table row
222 */
223 public function addElement($h, $icon, $data, $rowParams = '', $_ = '', $_2 = '', $colType = 'td')
224 {
225 $colType = ($colType === 'th') ? 'th' : 'td';
226 $noWrap = $this->no_noWrap ? '' : ' nowrap="nowrap"';
227 // Start up:
228 $parent = isset($data['parent']) ? (int)$data['parent'] : 0;
229 $out = '
230 <!-- Element, begin: -->
231 <tr ' . $rowParams . ' data-uid="' . (int)$data['uid'] . '" data-l10nparent="' . $parent . '">';
232 // Show icon and lines
233 if ($this->showIcon) {
234 $out .= '
235 <' . $colType . ' nowrap="nowrap" class="col-icon">';
236 if (!$h) {
237 $out .= '&nbsp;';
238 } else {
239 for ($a = 0; $a < $h; $a++) {
240 if (!$a) {
241 if ($icon) {
242 $out .= $icon;
243 }
244 } else {
245 }
246 }
247 }
248 $out .= '</' . $colType . '>
249 ';
250 }
251 // Init rendering.
252 $colsp = '';
253 $lastKey = '';
254 $c = 0;
255 $ccount = 0;
256 // __label is used as the label key to circumvent problems with uid used as label (see #67756)
257 // as it was introduced later on, check if it really exists before using it
258 $fields = $this->fieldArray;
259 if ($colType === 'td' && array_key_exists('__label', $data)) {
260 $fields[0] = '__label';
261 }
262 // Traverse field array which contains the data to present:
263 foreach ($fields as $vKey) {
264 if (isset($data[$vKey])) {
265 if ($lastKey) {
266 $cssClass = $this->addElement_tdCssClass[$lastKey];
267 if ($this->oddColumnsCssClass && $ccount % 2 == 0) {
268 $cssClass = implode(' ', array($this->addElement_tdCssClass[$lastKey], $this->oddColumnsCssClass));
269 }
270 $out .= '
271 <' . $colType . $noWrap . ' class="' . $cssClass . '"' . $colsp . $this->addElement_tdParams[$lastKey] . '>' . $data[$lastKey] . '</' . $colType . '>';
272 }
273 $lastKey = $vKey;
274 $c = 1;
275 $ccount++;
276 } else {
277 if (!$lastKey) {
278 $lastKey = $vKey;
279 }
280 $c++;
281 }
282 if ($c > 1) {
283 $colsp = ' colspan="' . $c . '"';
284 } else {
285 $colsp = '';
286 }
287 }
288 if ($lastKey) {
289 $cssClass = $this->addElement_tdCssClass[$lastKey];
290 if ($this->oddColumnsCssClass) {
291 $cssClass = implode(' ', array($this->addElement_tdCssClass[$lastKey], $this->oddColumnsCssClass));
292 }
293 $out .= '
294 <' . $colType . $noWrap . ' class="' . $cssClass . '"' . $colsp . $this->addElement_tdParams[$lastKey] . '>' . $data[$lastKey] . '</' . $colType . '>';
295 }
296 // End row
297 $out .= '
298 </tr>';
299 // Return row.
300 return $out;
301 }
302
303 /**
304 * Dummy function, used to write the top of a table listing.
305 *
306 * @return void
307 */
308 public function writeTop()
309 {
310 }
311
312 /**
313 * Creates a forward/reverse button based on the status of ->eCounter, ->firstElementNumber, ->iLimit
314 *
315 * @param string $table Table name
316 * @return array array([boolean], [HTML]) where [boolean] is 1 for reverse element, [HTML] is the table-row code for the element
317 */
318 public function fwd_rwd_nav($table = '')
319 {
320 $code = '';
321 if ($this->eCounter >= $this->firstElementNumber && $this->eCounter < $this->firstElementNumber + $this->iLimit) {
322 if ($this->firstElementNumber && $this->eCounter == $this->firstElementNumber) {
323 // Reverse
324 $theData = array();
325 $titleCol = $this->fieldArray[0];
326 $theData[$titleCol] = $this->fwd_rwd_HTML('fwd', $this->eCounter, $table);
327 $code = $this->addElement(1, '', $theData, 'class="fwd_rwd_nav"');
328 }
329 return array(1, $code);
330 } else {
331 if ($this->eCounter == $this->firstElementNumber + $this->iLimit) {
332 // Forward
333 $theData = array();
334 $titleCol = $this->fieldArray[0];
335 $theData[$titleCol] = $this->fwd_rwd_HTML('rwd', $this->eCounter, $table);
336 $code = $this->addElement(1, '', $theData, 'class="fwd_rwd_nav"');
337 }
338 return array(0, $code);
339 }
340 }
341
342 /**
343 * Creates the button with link to either forward or reverse
344 *
345 * @param string $type Type: "fwd" or "rwd
346 * @param int $pointer Pointer
347 * @param string $table Table name
348 * @return string
349 * @access private
350 */
351 public function fwd_rwd_HTML($type, $pointer, $table = '')
352 {
353 $content = '';
354 $tParam = $table ? '&table=' . rawurlencode($table) : '';
355 switch ($type) {
356 case 'fwd':
357 $href = $this->listURL() . '&pointer=' . ($pointer - $this->iLimit) . $tParam;
358 $content = '<a href="' . htmlspecialchars($href) . '">' . $this->iconFactory->getIcon('actions-move-up', Icon::SIZE_SMALL)->render() . '</a> <i>[1 - ' . $pointer . ']</i>';
359 break;
360 case 'rwd':
361 $href = $this->listURL() . '&pointer=' . $pointer . $tParam;
362 $content = '<a href="' . htmlspecialchars($href) . '">' . $this->iconFactory->getIcon('actions-move-down', Icon::SIZE_SMALL)->render() . '</a> <i>[' . ($pointer + 1) . ' - ' . $this->totalItems . ']</i>';
363 break;
364 }
365 return $content;
366 }
367
368 /**
369 * Creates the URL to this script, including all relevant GPvars
370 *
371 * @param string $altId Alternative id value. Enter blank string for the current id ($this->id)
372 * @param string $table Table name to display. Enter "-1" for the current table.
373 * @param string $exclList Comma separated list of fields NOT to include ("sortField", "sortRev" or "firstElementNumber")
374 * @return string URL
375 */
376 public function listURL($altId = '', $table = '-1', $exclList = '')
377 {
378 return $this->getThisScript() . 'id=' . ($altId !== '' ? $altId : $this->id);
379 }
380
381 /**
382 * Returning JavaScript for ClipBoard functionality.
383 *
384 * @return string
385 */
386 public function CBfunctions()
387 {
388 return '
389 // checkOffCB()
390 function checkOffCB(listOfCBnames, link) { //
391 var checkBoxes, flag, i;
392 var checkBoxes = listOfCBnames.split(",");
393 if (link.rel === "") {
394 link.rel = "allChecked";
395 flag = true;
396 } else {
397 link.rel = "";
398 flag = false;
399 }
400 for (i = 0; i < checkBoxes.length; i++) {
401 setcbValue(checkBoxes[i], flag);
402 }
403 }
404 // cbValue()
405 function cbValue(CBname) { //
406 var CBfullName = "CBC["+CBname+"]";
407 return (document.dblistForm[CBfullName] && document.dblistForm[CBfullName].checked ? 1 : 0);
408 }
409 // setcbValue()
410 function setcbValue(CBname,flag) { //
411 CBfullName = "CBC["+CBname+"]";
412 if(document.dblistForm[CBfullName]) {
413 document.dblistForm[CBfullName].checked = flag ? "on" : 0;
414 }
415 }
416
417 ';
418 }
419
420 /**
421 * Initializes page languages and icons
422 *
423 * @return void
424 */
425 public function initializeLanguages()
426 {
427 // Look up page overlays:
428 $this->pageOverlays = $this->getDatabaseConnection()->exec_SELECTgetRows('*', 'pages_language_overlay', 'pid=' . (int)$this->id . BackendUtility::deleteClause('pages_language_overlay') . BackendUtility::versioningPlaceholderClause('pages_language_overlay'), '', '', '', 'sys_language_uid');
429 $this->languageIconTitles = $this->getTranslateTools()->getSystemLanguages($this->id);
430 }
431
432 /**
433 * Return the icon for the language
434 *
435 * @param int $sys_language_uid Sys language uid
436 * @param bool $addAsAdditionalText If set to true, only the flag is returned
437 * @return string Language icon
438 */
439 public function languageFlag($sys_language_uid, $addAsAdditionalText = true)
440 {
441 $out = '';
442 $title = htmlspecialchars($this->languageIconTitles[$sys_language_uid]['title']);
443 if ($this->languageIconTitles[$sys_language_uid]['flagIcon']) {
444 $out .= '<span title="' . $title . '">' . $this->iconFactory->getIcon($this->languageIconTitles[$sys_language_uid]['flagIcon'], Icon::SIZE_SMALL)->render() . '</span>';
445 if (!$addAsAdditionalText) {
446 return $out;
447 }
448 $out .= '&nbsp;';
449 }
450 $out .= $title;
451 return $out;
452 }
453
454 /**
455 * Gets an instance of TranslationConfigurationProvider
456 *
457 * @return TranslationConfigurationProvider
458 */
459 protected function getTranslateTools()
460 {
461 if (!isset($this->translateTools)) {
462 $this->translateTools = GeneralUtility::makeInstance(TranslationConfigurationProvider::class);
463 }
464 return $this->translateTools;
465 }
466
467 /**
468 * Generates HTML code for a Reference tooltip out of
469 * sys_refindex records you hand over
470 *
471 * @param int $references number of records from sys_refindex table
472 * @param string $launchViewParameter JavaScript String, which will be passed as parameters to top.launchView
473 * @return string
474 */
475 protected function generateReferenceToolTip($references, $launchViewParameter = '')
476 {
477 if (!$references) {
478 $htmlCode = '-';
479 } else {
480 $htmlCode = '<a href="#"';
481 if ($launchViewParameter !== '') {
482 $htmlCode .= ' onclick="' . htmlspecialchars(('top.launchView(' . $launchViewParameter . '); return false;')) . '"';
483 }
484 $htmlCode .= ' title="' . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang.xlf:show_references') . ' (' . $references . ')') . '">';
485 $htmlCode .= $references;
486 $htmlCode .= '</a>';
487 }
488 return $htmlCode;
489 }
490
491 /**
492 * Returns the language service
493 * @return LanguageService
494 */
495 protected function getLanguageService()
496 {
497 return $GLOBALS['LANG'];
498 }
499
500 /**
501 * Returns the database connection
502 *
503 * @return DatabaseConnection
504 */
505 protected function getDatabaseConnection()
506 {
507 return $GLOBALS['TYPO3_DB'];
508 }
509 }