[BUGFIX] TSConfig for fields with a dot in the name does not work
[Packages/TYPO3.CMS.git] / typo3 / sysext / recordlist / Classes / RecordList / DatabaseRecordList.php
1 <?php
2 namespace TYPO3\CMS\Recordlist\RecordList;
3
4 /*************************************************************
5 * Copyright notice
6 *
7 * (c) 1999-2013 Kasper Skårhøj (kasperYYYY@typo3.com)
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 * A copy is found in the textfile GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29 /**
30 * Class for rendering of Web>List module
31 *
32 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
33 */
34 class DatabaseRecordList extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRecordList {
35
36 // External:
37 // If TRUE, table rows in the list will alternate in background colors (and have background colors at all!)
38 /**
39 * @todo Define visibility
40 */
41 public $alternateBgColors = FALSE;
42
43 // Used to indicate which tables (values in the array) that can have a create-new-record link. If the array is empty, all tables are allowed.
44 /**
45 * @todo Define visibility
46 */
47 public $allowedNewTables = array();
48
49 // Used to indicate which tables (values in the array) that cannot have a create-new-record link. If the array is empty, all tables are allowed.
50 /**
51 * @todo Define visibility
52 */
53 public $deniedNewTables = array();
54
55 // If TRUE, the control panel will contain links to the create-new wizards for pages and tt_content elements (normally, the link goes to just creating a new element without the wizards!).
56 /**
57 * @todo Define visibility
58 */
59 public $newWizards = FALSE;
60
61 // If TRUE, will disable the rendering of clipboard + control panels.
62 /**
63 * @todo Define visibility
64 */
65 public $dontShowClipControlPanels = FALSE;
66
67 // If TRUE, will show the clipboard in the field list.
68 /**
69 * @todo Define visibility
70 */
71 public $showClipboard = FALSE;
72
73 // If TRUE, will DISABLE all control panels in lists. (Takes precedence)
74 /**
75 * @todo Define visibility
76 */
77 public $noControlPanels = FALSE;
78
79 // If TRUE, clickmenus will be rendered
80 /**
81 * @todo Define visibility
82 */
83 public $clickMenuEnabled = TRUE;
84
85 // Count of record rows in view
86 /**
87 * @todo Define visibility
88 */
89 public $totalRowCount;
90
91 // Space icon used for alignment
92 /**
93 * @todo Define visibility
94 */
95 public $spaceIcon;
96
97 // Internal:
98 // Set to the page record (see writeTop())
99 /**
100 * @todo Define visibility
101 */
102 public $pageRow = array();
103
104 // Used to accumulate CSV lines for CSV export.
105 protected $csvLines = array();
106
107 // If set, the listing is returned as CSV instead.
108 /**
109 * @todo Define visibility
110 */
111 public $csvOutput = FALSE;
112
113 /**
114 * Clipboard object
115 *
116 * @var \TYPO3\CMS\Backend\Clipboard\Clipboard
117 * @todo Define visibility
118 */
119 public $clipObj;
120
121 // Tracking names of elements (for clipboard use)
122 /**
123 * @todo Define visibility
124 */
125 public $CBnames = array();
126
127 // Used to track which elements has duplicates and how many
128 /**
129 * @todo Define visibility
130 */
131 public $duplicateStack = array();
132
133 /**
134 * [$tablename][$uid] = number of references to this record
135 *
136 * @var array
137 */
138 protected $referenceCount = array();
139
140 // Translations of the current record
141 /**
142 * @todo Define visibility
143 */
144 public $translations;
145
146 // select fields for the query which fetches the translations of the current record
147 /**
148 * @todo Define visibility
149 */
150 public $selFieldList;
151
152 public $disableSingleTableView = FALSE;
153
154 /**
155 * Create the panel of buttons for submitting the form or otherwise perform operations.
156 *
157 * @return array All available buttons as an assoc. array
158 */
159 public function getButtons() {
160 $buttons = array(
161 'csh' => '',
162 'view' => '',
163 'edit' => '',
164 'hide_unhide' => '',
165 'move' => '',
166 'new_record' => '',
167 'paste' => '',
168 'level_up' => '',
169 'cache' => '',
170 'reload' => '',
171 'shortcut' => '',
172 'back' => '',
173 'csv' => '',
174 'export' => ''
175 );
176 // Get users permissions for this page record:
177 $localCalcPerms = $GLOBALS['BE_USER']->calcPerms($this->pageRow);
178 // CSH
179 if (!strlen($this->id)) {
180 $buttons['csh'] = \TYPO3\CMS\Backend\Utility\BackendUtility::cshItem('xMOD_csh_corebe', 'list_module_noId', $GLOBALS['BACK_PATH'], '', TRUE);
181 } elseif (!$this->id) {
182 $buttons['csh'] = \TYPO3\CMS\Backend\Utility\BackendUtility::cshItem('xMOD_csh_corebe', 'list_module_root', $GLOBALS['BACK_PATH'], '', TRUE);
183 } else {
184 $buttons['csh'] = \TYPO3\CMS\Backend\Utility\BackendUtility::cshItem('xMOD_csh_corebe', 'list_module', $GLOBALS['BACK_PATH'], '', TRUE);
185 }
186 if (isset($this->id)) {
187 // View Exclude doktypes 254,255 Configuration: mod.web_list.noViewWithDokTypes = 254,255
188 if (isset($GLOBALS['SOBE']->modTSconfig['properties']['noViewWithDokTypes'])) {
189 $noViewDokTypes = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $GLOBALS['SOBE']->modTSconfig['properties']['noViewWithDokTypes'], TRUE);
190 } else {
191 //default exclusion: doktype 254 (folder), 255 (recycler)
192 $noViewDokTypes = array(\TYPO3\CMS\Frontend\Page\PageRepository::DOKTYPE_SYSFOLDER, \TYPO3\CMS\Frontend\Page\PageRepository::DOKTYPE_RECYCLER);
193 }
194 if (!in_array($this->pageRow['doktype'], $noViewDokTypes)) {
195 $buttons['view'] = '<a href="#" onclick="' . htmlspecialchars(\TYPO3\CMS\Backend\Utility\BackendUtility::viewOnClick($this->id, $this->backPath, \TYPO3\CMS\Backend\Utility\BackendUtility::BEgetRootLine($this->id))) . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.showPage', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-view') . '</a>';
196 }
197 // New record
198 if (!$GLOBALS['SOBE']->modTSconfig['properties']['noCreateRecordsLink']) {
199 $buttons['new_record'] = '<a href="#" onclick="' . htmlspecialchars(('return jumpExt(\'' . $this->backPath . 'db_new.php?id=' . $this->id . '\');')) . '" title="' . $GLOBALS['LANG']->getLL('newRecordGeneral', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-new') . '</a>';
200 }
201 // If edit permissions are set (see class.t3lib_userauthgroup.php)
202 if ($localCalcPerms & 2 && !empty($this->id)) {
203 // Edit
204 $params = '&edit[pages][' . $this->pageRow['uid'] . ']=edit';
205 $buttons['edit'] = '<a href="#" onclick="' . htmlspecialchars(\TYPO3\CMS\Backend\Utility\BackendUtility::editOnClick($params, $this->backPath, -1)) . '" title="' . $GLOBALS['LANG']->getLL('editPage', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-page-open') . '</a>';
206 }
207 // Paste
208 if ($localCalcPerms & 8 || $localCalcPerms & 16) {
209 $elFromTable = $this->clipObj->elFromTable('');
210 if (count($elFromTable)) {
211 $buttons['paste'] = '<a href="' . htmlspecialchars($this->clipObj->pasteUrl('', $this->id)) . '" onclick="' . htmlspecialchars(('return ' . $this->clipObj->confirmMsg('pages', $this->pageRow, 'into', $elFromTable))) . '" title="' . $GLOBALS['LANG']->getLL('clip_paste', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-paste-after') . '</a>';
212 }
213 }
214 // Cache
215 $buttons['cache'] = '<a href="' . htmlspecialchars(($this->listURL() . '&clear_cache=1')) . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.clear_cache', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-system-cache-clear') . '</a>';
216 if ($this->table) {
217 // CSV
218 $buttons['csv'] = '<a href="' . htmlspecialchars(($this->listURL() . '&csv=1')) . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.csv', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('mimetypes-text-csv') . '</a>';
219 // Export
220 if (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('impexp')) {
221 $url = $this->backPath . \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath('impexp') . 'app/index.php?tx_impexp[action]=export';
222 $buttons['export'] = '<a href="' . htmlspecialchars(($url . '&tx_impexp[list][]=' . rawurlencode(($this->table . ':' . $this->id)))) . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:rm.export', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-export-t3d') . '</a>';
223 }
224 }
225 // Reload
226 $buttons['reload'] = '<a href="' . htmlspecialchars($this->listURL()) . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.reload', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-system-refresh') . '</a>';
227 // Shortcut
228 if ($GLOBALS['BE_USER']->mayMakeShortcut()) {
229 $buttons['shortcut'] = $GLOBALS['TBE_TEMPLATE']->makeShortcutIcon('id, imagemode, pointer, table, search_field, search_levels, showLimit, sortField, sortRev', implode(',', array_keys($this->MOD_MENU)), 'web_list');
230 }
231 // Back
232 if ($this->returnUrl) {
233 $buttons['back'] = '<a href="' . htmlspecialchars(\TYPO3\CMS\Core\Utility\GeneralUtility::linkThisUrl($this->returnUrl, array('id' => $this->id))) . '" class="typo3-goBack" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.goBack', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-view-go-back') . '</a>';
234 }
235 }
236 return $buttons;
237 }
238
239 /**
240 * Creates the listing of records from a single table
241 *
242 * @param string $table Table name
243 * @param integer $id Page id
244 * @param string $rowlist List of fields to show in the listing. Pseudo fields will be added including the record header.
245 * @return string HTML table with the listing for the record.
246 * @todo Define visibility
247 */
248 public function getTable($table, $id, $rowlist) {
249 // Init
250 $addWhere = '';
251 $titleCol = $GLOBALS['TCA'][$table]['ctrl']['label'];
252 $thumbsCol = $GLOBALS['TCA'][$table]['ctrl']['thumbnail'];
253 $l10nEnabled = $GLOBALS['TCA'][$table]['ctrl']['languageField'] && $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] && !$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerTable'];
254 $tableCollapsed = !$this->tablesCollapsed[$table] ? FALSE : TRUE;
255 // prepare space icon
256 $this->spaceIcon = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('empty-empty', array('style' => 'background-position: 0 10px;'));
257 // Cleaning rowlist for duplicates and place the $titleCol as the first column always!
258 $this->fieldArray = array();
259 // title Column
260 // Add title column
261 $this->fieldArray[] = $titleCol;
262 // Control-Panel
263 if (!\TYPO3\CMS\Core\Utility\GeneralUtility::inList($rowlist, '_CONTROL_')) {
264 $this->fieldArray[] = '_CONTROL_';
265 $this->fieldArray[] = '_AFTERCONTROL_';
266 }
267 // Clipboard
268 if ($this->showClipboard) {
269 $this->fieldArray[] = '_CLIPBOARD_';
270 }
271 // Ref
272 if (!$this->dontShowClipControlPanels) {
273 $this->fieldArray[] = '_REF_';
274 $this->fieldArray[] = '_AFTERREF_';
275 }
276 // Path
277 if ($this->searchLevels) {
278 $this->fieldArray[] = '_PATH_';
279 }
280 // Localization
281 if ($this->localizationView && $l10nEnabled) {
282 $this->fieldArray[] = '_LOCALIZATION_';
283 $this->fieldArray[] = '_LOCALIZATION_b';
284 $addWhere .= ' AND (
285 ' . $GLOBALS['TCA'][$table]['ctrl']['languageField'] . '<=0
286 OR
287 ' . $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] . ' = 0
288 )';
289 }
290 // Cleaning up:
291 $this->fieldArray = array_unique(array_merge($this->fieldArray, \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $rowlist, 1)));
292 if ($this->noControlPanels) {
293 $tempArray = array_flip($this->fieldArray);
294 unset($tempArray['_CONTROL_']);
295 unset($tempArray['_CLIPBOARD_']);
296 $this->fieldArray = array_keys($tempArray);
297 }
298 // Creating the list of fields to include in the SQL query:
299 $selectFields = $this->fieldArray;
300 $selectFields[] = 'uid';
301 $selectFields[] = 'pid';
302 // adding column for thumbnails
303 if ($thumbsCol) {
304 $selectFields[] = $thumbsCol;
305 }
306 if ($table == 'pages') {
307 if (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('cms')) {
308 $selectFields[] = 'module';
309 $selectFields[] = 'extendToSubpages';
310 $selectFields[] = 'nav_hide';
311 }
312 $selectFields[] = 'doktype';
313 }
314 if (is_array($GLOBALS['TCA'][$table]['ctrl']['enablecolumns'])) {
315 $selectFields = array_merge($selectFields, $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']);
316 }
317 if ($GLOBALS['TCA'][$table]['ctrl']['type']) {
318 $selectFields[] = $GLOBALS['TCA'][$table]['ctrl']['type'];
319 }
320 if ($GLOBALS['TCA'][$table]['ctrl']['typeicon_column']) {
321 $selectFields[] = $GLOBALS['TCA'][$table]['ctrl']['typeicon_column'];
322 }
323 if ($GLOBALS['TCA'][$table]['ctrl']['versioningWS']) {
324 $selectFields[] = 't3ver_id';
325 $selectFields[] = 't3ver_state';
326 $selectFields[] = 't3ver_wsid';
327 }
328 if ($l10nEnabled) {
329 $selectFields[] = $GLOBALS['TCA'][$table]['ctrl']['languageField'];
330 $selectFields[] = $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'];
331 }
332 if ($GLOBALS['TCA'][$table]['ctrl']['label_alt']) {
333 $selectFields = array_merge($selectFields, \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$table]['ctrl']['label_alt'], 1));
334 }
335 // Unique list!
336 $selectFields = array_unique($selectFields);
337 $fieldListFields = $this->makeFieldList($table, 1);
338 if (empty($fieldListFields) && $GLOBALS['TYPO3_CONF_VARS']['BE']['debug']) {
339 $message = sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_web_list.php:missingTcaColumnsMessage', TRUE), $table, $table);
340 $messageTitle = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_web_list.php:missingTcaColumnsMessageTitle', TRUE);
341 $flashMessage = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Messaging\\FlashMessage', $message, $messageTitle, \TYPO3\CMS\Core\Messaging\FlashMessage::WARNING, TRUE);
342 /** @var \TYPO3\CMS\Core\Messaging\FlashMessage $flashMessage */
343 \TYPO3\CMS\Core\Messaging\FlashMessageQueue::addMessage($flashMessage);
344 }
345 // Making sure that the fields in the field-list ARE in the field-list from TCA!
346 $selectFields = array_intersect($selectFields, $fieldListFields);
347 // Implode it into a list of fields for the SQL-statement.
348 $selFieldList = implode(',', $selectFields);
349 $this->selFieldList = $selFieldList;
350 /**
351 * @hook DB-List getTable
352 * @date 2007-11-16
353 * @request Malte Jansen <mail@maltejansen.de>
354 */
355 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['getTable'])) {
356 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['getTable'] as $classData) {
357 $hookObject = \TYPO3\CMS\Core\Utility\GeneralUtility::getUserObj($classData);
358 if (!$hookObject instanceof \TYPO3\CMS\Backend\RecordList\RecordListGetTableHookInterface) {
359 throw new \UnexpectedValueException('$hookObject must implement interface TYPO3\\CMS\\Backend\\RecordList\\RecordListGetTableHookInterface', 1195114460);
360 }
361 $hookObject->getDBlistQuery($table, $id, $addWhere, $selFieldList, $this);
362 }
363 }
364 // Create the SQL query for selecting the elements in the listing:
365 // do not do paging when outputting as CSV
366 if ($this->csvOutput) {
367 $this->iLimit = 0;
368 }
369 if ($this->firstElementNumber > 2 && $this->iLimit > 0) {
370 // Get the two previous rows for sorting if displaying page > 1
371 $this->firstElementNumber = $this->firstElementNumber - 2;
372 $this->iLimit = $this->iLimit + 2;
373 // (API function from class.db_list.inc)
374 $queryParts = $this->makeQueryArray($table, $id, $addWhere, $selFieldList);
375 $this->firstElementNumber = $this->firstElementNumber + 2;
376 $this->iLimit = $this->iLimit - 2;
377 } else {
378 // (API function from class.db_list.inc)
379 $queryParts = $this->makeQueryArray($table, $id, $addWhere, $selFieldList);
380 }
381 // Finding the total amount of records on the page (API function from class.db_list.inc)
382 $this->setTotalItems($queryParts);
383 // Init:
384 $dbCount = 0;
385 $out = '';
386 $listOnlyInSingleTableMode = $this->listOnlyInSingleTableMode && !$this->table;
387 // If the count query returned any number of records, we perform the real query, selecting records.
388 if ($this->totalItems) {
389 // Fetch records only if not in single table mode or if in multi table mode and not collapsed
390 if ($listOnlyInSingleTableMode || !$this->table && $tableCollapsed) {
391 $dbCount = $this->totalItems;
392 } else {
393 // Set the showLimit to the number of records when outputting as CSV
394 if ($this->csvOutput) {
395 $this->showLimit = $this->totalItems;
396 $this->iLimit = $this->totalItems;
397 }
398 $result = $GLOBALS['TYPO3_DB']->exec_SELECT_queryArray($queryParts);
399 $dbCount = $GLOBALS['TYPO3_DB']->sql_num_rows($result);
400 }
401 }
402 // If any records was selected, render the list:
403 if ($dbCount) {
404 // Half line is drawn between tables:
405 if (!$listOnlyInSingleTableMode) {
406 $theData = array();
407 if (!$this->table && !$rowlist) {
408 $theData[$titleCol] = '<img src="clear.gif" width="' . ($GLOBALS['SOBE']->MOD_SETTINGS['bigControlPanel'] ? '230' : '350') . '" height="1" alt="" />';
409 if (in_array('_CONTROL_', $this->fieldArray)) {
410 $theData['_CONTROL_'] = '';
411 }
412 if (in_array('_CLIPBOARD_', $this->fieldArray)) {
413 $theData['_CLIPBOARD_'] = '';
414 }
415 }
416 $out .= $this->addelement(0, '', $theData, 'class="c-table-row-spacer"', $this->leftMargin);
417 }
418 $tableTitle = $GLOBALS['LANG']->sL($GLOBALS['TCA'][$table]['ctrl']['title'], TRUE);
419 if ($tableTitle === '') {
420 $tableTitle = $table;
421 }
422 // Header line is drawn
423 $theData = array();
424 if ($this->disableSingleTableView) {
425 $theData[$titleCol] = '<span class="c-table">' . \TYPO3\CMS\Backend\Utility\BackendUtility::wrapInHelp($table, '', $tableTitle) . '</span> (' . $this->totalItems . ')';
426 } else {
427 $theData[$titleCol] = $this->linkWrapTable($table, '<span class="c-table">' . $tableTitle . '</span> (' . $this->totalItems . ') ' . ($this->table ? \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-view-table-collapse', array('title' => $GLOBALS['LANG']->getLL('contractView', TRUE))) : \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-view-table-expand', array('title' => $GLOBALS['LANG']->getLL('expandView', TRUE)))));
428 }
429 if ($listOnlyInSingleTableMode) {
430 $out .= '
431 <tr>
432 <td class="t3-row-header" style="width:95%;">' . \TYPO3\CMS\Backend\Utility\BackendUtility::wrapInHelp($table, '', $theData[$titleCol]) . '</td>
433 </tr>';
434 } else {
435 // Render collapse button if in multi table mode
436 $collapseIcon = '';
437 if (!$this->table) {
438 $collapseIcon = '<a href="' . htmlspecialchars(($this->listURL() . '&collapse[' . $table . ']=' . ($tableCollapsed ? '0' : '1'))) . '" title="' . ($tableCollapsed ? $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.expandTable', TRUE) : $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.collapseTable', TRUE)) . '">' . ($tableCollapsed ? \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-view-list-expand', array('class' => 'collapseIcon')) : \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-view-list-collapse', array('class' => 'collapseIcon'))) . '</a>';
439 }
440 $out .= $this->addElement(1, $collapseIcon, $theData, ' class="t3-row-header"', '');
441 }
442 // Render table rows only if in multi table view and not collapsed or if in single table view
443 if (!$listOnlyInSingleTableMode && (!$tableCollapsed || $this->table)) {
444 // Fixing a order table for sortby tables
445 $this->currentTable = array();
446 $currentIdList = array();
447 $doSort = $GLOBALS['TCA'][$table]['ctrl']['sortby'] && !$this->sortField;
448 $prevUid = 0;
449 $prevPrevUid = 0;
450 // Get first two rows and initialize prevPrevUid and prevUid if on page > 1
451 if ($this->firstElementNumber > 2 && $this->iLimit > 0) {
452 $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result);
453 $prevPrevUid = -((int) $row['uid']);
454 $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result);
455 $prevUid = $row['uid'];
456 }
457 $accRows = array();
458 // Accumulate rows here
459 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result)) {
460 if (!$this->isRowListingConditionFulfilled($table, $row)) {
461 continue;
462 }
463 // In offline workspace, look for alternative record:
464 \TYPO3\CMS\Backend\Utility\BackendUtility::workspaceOL($table, $row, $GLOBALS['BE_USER']->workspace, TRUE);
465 if (is_array($row)) {
466 $accRows[] = $row;
467 $currentIdList[] = $row['uid'];
468 if ($doSort) {
469 if ($prevUid) {
470 $this->currentTable['prev'][$row['uid']] = $prevPrevUid;
471 $this->currentTable['next'][$prevUid] = '-' . $row['uid'];
472 $this->currentTable['prevUid'][$row['uid']] = $prevUid;
473 }
474 $prevPrevUid = isset($this->currentTable['prev'][$row['uid']]) ? -$prevUid : $row['pid'];
475 $prevUid = $row['uid'];
476 }
477 }
478 }
479 $GLOBALS['TYPO3_DB']->sql_free_result($result);
480 $this->totalRowCount = count($accRows);
481 // CSV initiated
482 if ($this->csvOutput) {
483 $this->initCSV();
484 }
485 // Render items:
486 $this->CBnames = array();
487 $this->duplicateStack = array();
488 $this->eCounter = $this->firstElementNumber;
489 $iOut = '';
490 $cc = 0;
491 foreach ($accRows as $row) {
492 // Render item row if counter < limit
493 if ($cc < $this->iLimit) {
494 $cc++;
495 $this->translations = FALSE;
496 $iOut .= $this->renderListRow($table, $row, $cc, $titleCol, $thumbsCol);
497 // If localization view is enabled it means that the selected records are
498 // either default or All language and here we will not select translations
499 // which point to the main record:
500 if ($this->localizationView && $l10nEnabled) {
501 // For each available translation, render the record:
502 if (is_array($this->translations)) {
503 foreach ($this->translations as $lRow) {
504 // $lRow isn't always what we want - if record was moved we've to work with the
505 // placeholder records otherwise the list is messed up a bit
506 if ($row['_MOVE_PLH_uid'] && $row['_MOVE_PLH_pid']) {
507 $tmpRow = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecordRaw($table, 't3ver_move_id="' . intval($lRow['uid']) . '" AND pid="' . $row['_MOVE_PLH_pid'] . '" AND t3ver_wsid=' . $row['t3ver_wsid'] . \TYPO3\CMS\Backend\Utility\BackendUtility::deleteClause($table), $selFieldList);
508 $lRow = is_array($tmpRow) ? $tmpRow : $lRow;
509 }
510 // In offline workspace, look for alternative record:
511 \TYPO3\CMS\Backend\Utility\BackendUtility::workspaceOL($table, $lRow, $GLOBALS['BE_USER']->workspace, TRUE);
512 if (is_array($lRow) && $GLOBALS['BE_USER']->checkLanguageAccess($lRow[$GLOBALS['TCA'][$table]['ctrl']['languageField']])) {
513 $currentIdList[] = $lRow['uid'];
514 $iOut .= $this->renderListRow($table, $lRow, $cc, $titleCol, $thumbsCol, 18);
515 }
516 }
517 }
518 }
519 }
520 // Counter of total rows incremented:
521 $this->eCounter++;
522 }
523 // Record navigation is added to the beginning and end of the table if in single table mode
524 if ($this->table) {
525 $iOut = $this->renderListNavigation('top') . $iOut . $this->renderListNavigation('bottom');
526 } else {
527 // Show that there are more records than shown
528 if ($this->totalItems > $this->itemsLimitPerTable) {
529 $countOnFirstPage = $this->totalItems > $this->itemsLimitSingleTable ? $this->itemsLimitSingleTable : $this->totalItems;
530 $hasMore = $this->totalItems > $this->itemsLimitSingleTable;
531 $iOut .= '<tr><td colspan="' . count($this->fieldArray) . '" style="padding:5px;">
532 <a href="' . htmlspecialchars(($this->listURL() . '&table=' . rawurlencode($table))) . '">' . '<img' . \TYPO3\CMS\Backend\Utility\IconUtility::skinImg($this->backPath, 'gfx/pildown.gif', 'width="14" height="14"') . ' alt="" />' . ' <i>[1 - ' . $countOnFirstPage . ($hasMore ? '+' : '') . ']</i></a>
533 </td></tr>';
534 }
535 }
536 // The header row for the table is now created:
537 $out .= $this->renderListHeader($table, $currentIdList);
538 }
539 // The list of records is added after the header:
540 $out .= $iOut;
541 unset($iOut);
542 // ... and it is all wrapped in a table:
543 $out = '
544
545
546
547 <!--
548 DB listing of elements: "' . htmlspecialchars($table) . '"
549 -->
550 <table border="0" cellpadding="0" cellspacing="0" class="typo3-dblist' . ($listOnlyInSingleTableMode ? ' typo3-dblist-overview' : '') . '">
551 ' . $out . '
552 </table>';
553 // Output csv if...
554 // This ends the page with exit.
555 if ($this->csvOutput) {
556 $this->outputCSV($table);
557 }
558 }
559 // Return content:
560 return $out;
561 }
562
563 /**
564 * Check if all row listing conditions are fulfilled.
565 *
566 * This function serves as a dummy method to be overriden in extending classes.
567 *
568 * @param string $table Table name
569 * @param array $row Record
570 * @return boolean True, if all conditions are fulfilled.
571 */
572 protected function isRowListingConditionFulfilled($table, $row) {
573 return TRUE;
574 }
575
576 /**
577 * Rendering a single row for the list
578 *
579 * @param string $table Table name
580 * @param array $row Current record
581 * @param integer $cc Counter, counting for each time an element is rendered (used for alternating colors)
582 * @param string $titleCol Table field (column) where header value is found
583 * @param string $thumbsCol Table field (column) where (possible) thumbnails can be found
584 * @param integer $indent Indent from left.
585 * @return string Table row for the element
586 * @access private
587 * @see getTable()
588 * @todo Define visibility
589 */
590 public function renderListRow($table, $row, $cc, $titleCol, $thumbsCol, $indent = 0) {
591 $iOut = '';
592 // If in search mode, make sure the preview will show the correct page
593 if (strlen($this->searchString)) {
594 $id_orig = $this->id;
595 $this->id = $row['pid'];
596 }
597 if (is_array($row)) {
598 // Add special classes for first and last row
599 $rowSpecial = '';
600 if ($cc == 1 && $indent == 0) {
601 $rowSpecial .= ' firstcol';
602 }
603 if ($cc == $this->totalRowCount || $cc == $this->iLimit) {
604 $rowSpecial .= ' lastcol';
605 }
606 // Background color, if any:
607 if ($this->alternateBgColors) {
608 $row_bgColor = $cc % 2 ? ' class="db_list_normal' . $rowSpecial . '"' : ' class="db_list_alt' . $rowSpecial . '"';
609 } else {
610 $row_bgColor = ' class="db_list_normal' . $rowSpecial . '"';
611 }
612 // Overriding with versions background color if any:
613 $row_bgColor = $row['_CSSCLASS'] ? ' class="' . $row['_CSSCLASS'] . '"' : $row_bgColor;
614 // Incr. counter.
615 $this->counter++;
616 // The icon with link
617 $alttext = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecordIconAltText($row, $table);
618 $iconImg = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIconForRecord($table, $row, array('title' => htmlspecialchars($alttext), 'style' => $indent ? ' margin-left: ' . $indent . 'px;' : ''));
619 $theIcon = $this->clickMenuEnabled ? $GLOBALS['SOBE']->doc->wrapClickMenuOnIcon($iconImg, $table, $row['uid']) : $iconImg;
620 // Preparing and getting the data-array
621 $theData = array();
622 foreach ($this->fieldArray as $fCol) {
623 if ($fCol == $titleCol) {
624 $recTitle = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecordTitle($table, $row, FALSE, TRUE);
625 // If the record is edit-locked by another user, we will show a little warning sign:
626 if ($lockInfo = \TYPO3\CMS\Backend\Utility\BackendUtility::isRecordLocked($table, $row['uid'])) {
627 $warning = '<a href="#" onclick="' . htmlspecialchars(('alert(' . $GLOBALS['LANG']->JScharCode($lockInfo['msg']) . '); return false;')) . '" title="' . htmlspecialchars($lockInfo['msg']) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('status-warning-in-use') . '</a>';
628 }
629 $theData[$fCol] = $warning . $this->linkWrapItems($table, $row['uid'], $recTitle, $row);
630 // Render thumbsnails if a thumbnail column exists and there is content in it:
631 if ($this->thumbs && trim($row[$thumbsCol])) {
632 $theData[$fCol] .= '<br />' . $this->thumbCode($row, $table, $thumbsCol);
633 }
634 $localizationMarkerClass = '';
635 if (isset($GLOBALS['TCA'][$table]['ctrl']['languageField']) && $row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] != 0 && $row[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']] != 0) {
636 // It's a translated record with a language parent
637 $localizationMarkerClass = ' localization';
638 }
639 } elseif ($fCol == 'pid') {
640 $theData[$fCol] = $row[$fCol];
641 } elseif ($fCol == '_PATH_') {
642 $theData[$fCol] = $this->recPath($row['pid']);
643 } elseif ($fCol == '_REF_') {
644 $theData[$fCol] = $this->createReferenceHtml($table, $row['uid']);
645 } elseif ($fCol == '_CONTROL_') {
646 $theData[$fCol] = $this->makeControl($table, $row);
647 } elseif ($fCol == '_AFTERCONTROL_' || $fCol == '_AFTERREF_') {
648 $theData[$fCol] = '&nbsp;';
649 } elseif ($fCol == '_CLIPBOARD_') {
650 $theData[$fCol] = $this->makeClip($table, $row);
651 } elseif ($fCol == '_LOCALIZATION_') {
652 list($lC1, $lC2) = $this->makeLocalizationPanel($table, $row);
653 $theData[$fCol] = $lC1;
654 $theData[$fCol . 'b'] = $lC2;
655 } elseif ($fCol == '_LOCALIZATION_b') {
656
657 } else {
658 $tmpProc = \TYPO3\CMS\Backend\Utility\BackendUtility::getProcessedValueExtra($table, $fCol, $row[$fCol], 100, $row['uid']);
659 $theData[$fCol] = $this->linkUrlMail(htmlspecialchars($tmpProc), $row[$fCol]);
660 if ($this->csvOutput) {
661 $row[$fCol] = \TYPO3\CMS\Backend\Utility\BackendUtility::getProcessedValueExtra($table, $fCol, $row[$fCol], 0, $row['uid']);
662 }
663 }
664 }
665 // Reset the ID if it was overwritten
666 if (strlen($this->searchString)) {
667 $this->id = $id_orig;
668 }
669 // Add row to CSV list:
670 if ($this->csvOutput) {
671 $this->addToCSV($row, $table);
672 }
673 // Add classes to table cells
674 $this->addElement_tdCssClass[$titleCol] = 'col-title' . $localizationMarkerClass;
675 if (!$this->dontShowClipControlPanels) {
676 $this->addElement_tdCssClass['_CONTROL_'] = 'col-control';
677 $this->addElement_tdCssClass['_AFTERCONTROL_'] = 'col-control-space';
678 $this->addElement_tdCssClass['_CLIPBOARD_'] = 'col-clipboard';
679 }
680 $this->addElement_tdCssClass['_PATH_'] = 'col-path';
681 $this->addElement_tdCssClass['_LOCALIZATION_'] = 'col-localizationa';
682 $this->addElement_tdCssClass['_LOCALIZATION_b'] = 'col-localizationb';
683 // Create element in table cells:
684 $iOut .= $this->addelement(1, $theIcon, $theData, $row_bgColor);
685 // Finally, return table row element:
686 return $iOut;
687 }
688 }
689
690 /**
691 * Gets the number of records referencing the record with the UID $uid in
692 * the table $tableName.
693 *
694 * @param string $tableName
695 * @param integer $uid
696 * @return integer The number of references to record $uid in table
697 */
698 protected function getReferenceCount($tableName, $uid) {
699 if (!isset($this->referenceCount[$tableName][$uid])) {
700 $numberOfReferences = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows('*', 'sys_refindex', 'ref_table = ' . $GLOBALS['TYPO3_DB']->fullQuoteStr($tableName, 'sys_refindex') . ' AND ref_uid = ' . $uid . ' AND deleted = 0');
701 $this->referenceCount[$tableName][$uid] = $numberOfReferences;
702 }
703 return $this->referenceCount[$tableName][$uid];
704 }
705
706 /**
707 * Rendering the header row for a table
708 *
709 * @param string $table Table name
710 * @param array $currentIdList Array of the currently displayed uids of the table
711 * @return string Header table row
712 * @access private
713 * @see getTable()
714 * @todo Define visibility
715 */
716 public function renderListHeader($table, $currentIdList) {
717 // Init:
718 $theData = array();
719 // Traverse the fields:
720 foreach ($this->fieldArray as $fCol) {
721 // Calculate users permissions to edit records in the table:
722 $permsEdit = $this->calcPerms & ($table == 'pages' ? 2 : 16);
723 switch ((string) $fCol) {
724 case '_PATH_':
725 // Path
726 $theData[$fCol] = '<i>[' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels._PATH_', 1) . ']</i>';
727 break;
728 case '_REF_':
729 // References
730 $theData[$fCol] = '<i>[' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_file_list.xml:c__REF_', 1) . ']</i>';
731 break;
732 case '_LOCALIZATION_':
733 // Path
734 $theData[$fCol] = '<i>[' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels._LOCALIZATION_', 1) . ']</i>';
735 break;
736 case '_LOCALIZATION_b':
737 // Path
738 $theData[$fCol] = $GLOBALS['LANG']->getLL('Localize', 1);
739 break;
740 case '_CLIPBOARD_':
741 // Clipboard:
742 $cells = array();
743 // If there are elements on the clipboard for this table, then display the "paste into" icon:
744 $elFromTable = $this->clipObj->elFromTable($table);
745 if (count($elFromTable)) {
746 $cells['pasteAfter'] = '<a href="' . htmlspecialchars($this->clipObj->pasteUrl($table, $this->id)) . '" onclick="' . htmlspecialchars(('return ' . $this->clipObj->confirmMsg('pages', $this->pageRow, 'into', $elFromTable))) . '" title="' . $GLOBALS['LANG']->getLL('clip_paste', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-paste-after') . '</a>';
747 }
748 // If the numeric clipboard pads are enabled, display the control icons for that:
749 if ($this->clipObj->current != 'normal') {
750 // The "select" link:
751 $cells['copyMarked'] = $this->linkClipboardHeaderIcon(\TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-edit-copy', array('title' => $GLOBALS['LANG']->getLL('clip_selectMarked', TRUE))), $table, 'setCB');
752 // The "edit marked" link:
753 $editIdList = implode(',', $currentIdList);
754 $editIdList = '\'+editList(\'' . $table . '\',\'' . $editIdList . '\')+\'';
755 $params = '&edit[' . $table . '][' . $editIdList . ']=edit&disHelp=1';
756 $cells['edit'] = '<a href="#" onclick="' . htmlspecialchars(\TYPO3\CMS\Backend\Utility\BackendUtility::editOnClick($params, $this->backPath, -1)) . '" title="' . $GLOBALS['LANG']->getLL('clip_editMarked', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-open') . '</a>';
757 // The "Delete marked" link:
758 $cells['delete'] = $this->linkClipboardHeaderIcon(\TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-edit-delete', array('title' => $GLOBALS['LANG']->getLL('clip_deleteMarked', TRUE))), $table, 'delete', sprintf($GLOBALS['LANG']->getLL('clip_deleteMarkedWarning'), $GLOBALS['LANG']->sL($GLOBALS['TCA'][$table]['ctrl']['title'])));
759 // The "Select all" link:
760 $cells['markAll'] = '<a class="cbcCheckAll" rel="" href="#" onclick="' . htmlspecialchars(('checkOffCB(\'' . implode(',', $this->CBnames) . '\', this); return false;')) . '" title="' . $GLOBALS['LANG']->getLL('clip_markRecords', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-select') . '</a>';
761 } else {
762 $cells['empty'] = '';
763 }
764 /**
765 * @hook renderListHeaderActions: Allows to change the clipboard icons of the Web>List table headers
766 * @date 2007-11-20
767 * @request Bernhard Kraft <krafbt@kraftb.at>
768 * @usage Above each listed table in Web>List a header row is shown. This hook allows to modify the icons responsible for the clipboard functions (shown above the clipboard checkboxes when a clipboard other than "Normal" is selected), or other "Action" functions which perform operations on the listed records.
769 */
770 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['actions'])) {
771 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['actions'] as $classData) {
772 $hookObject = \TYPO3\CMS\Core\Utility\GeneralUtility::getUserObj($classData);
773 if (!$hookObject instanceof \TYPO3\CMS\Recordlist\RecordList\RecordListHookInterface) {
774 throw new \UnexpectedValueException('$hookObject must implement interface TYPO3\\CMS\\Recordlist\\RecordList\\RecordListHookInterface', 1195567850);
775 }
776 $cells = $hookObject->renderListHeaderActions($table, $currentIdList, $cells, $this);
777 }
778 }
779 $theData[$fCol] = implode('', $cells);
780 break;
781 case '_CONTROL_':
782 // Control panel:
783 if (!$GLOBALS['TCA'][$table]['ctrl']['readOnly']) {
784 // If new records can be created on this page, add links:
785 if ($this->calcPerms & ($table == 'pages' ? 8 : 16) && $this->showNewRecLink($table)) {
786 if ($table == 'tt_content' && $this->newWizards) {
787 // If mod.web_list.newContentWiz.overrideWithExtension is set, use that extension's create new content wizard instead:
788 $tmpTSc = \TYPO3\CMS\Backend\Utility\BackendUtility::getModTSconfig($this->pageinfo['uid'], 'mod.web_list');
789 $tmpTSc = $tmpTSc['properties']['newContentWiz.']['overrideWithExtension'];
790 $newContentWizScriptPath = $this->backPath . \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded($tmpTSc) ? \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath($tmpTSc) . 'mod1/db_new_content_el.php' : 'sysext/cms/layout/db_new_content_el.php';
791 $icon = '<a href="#" onclick="' . htmlspecialchars(('return jumpExt(\'' . $newContentWizScriptPath . '?id=' . $this->id . '\');')) . '" title="' . $GLOBALS['LANG']->getLL('new', TRUE) . '">' . ($table == 'pages' ? \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-page-new') : \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-new')) . '</a>';
792 } elseif ($table == 'pages' && $this->newWizards) {
793 $icon = '<a href="' . htmlspecialchars(($this->backPath . 'db_new.php?id=' . $this->id . '&pagesOnly=1&returnUrl=' . rawurlencode(\TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('REQUEST_URI')))) . '" title="' . $GLOBALS['LANG']->getLL('new', TRUE) . '">' . ($table == 'pages' ? \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-page-new') : \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-new')) . '</a>';
794 } else {
795 $params = '&edit[' . $table . '][' . $this->id . ']=new';
796 if ($table == 'pages_language_overlay') {
797 $params .= '&overrideVals[pages_language_overlay][doktype]=' . (int) $this->pageRow['doktype'];
798 }
799 $icon = '<a href="#" onclick="' . htmlspecialchars(\TYPO3\CMS\Backend\Utility\BackendUtility::editOnClick($params, $this->backPath, -1)) . '" title="' . $GLOBALS['LANG']->getLL('new', TRUE) . '">' . ($table == 'pages' ? \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-page-new') : \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-new')) . '</a>';
800 }
801 }
802 // If the table can be edited, add link for editing ALL SHOWN fields for all listed records:
803 if ($permsEdit && $this->table && is_array($currentIdList)) {
804 $editIdList = implode(',', $currentIdList);
805 if ($this->clipNumPane()) {
806 $editIdList = '\'+editList(\'' . $table . '\',\'' . $editIdList . '\')+\'';
807 }
808 $params = '&edit[' . $table . '][' . $editIdList . ']=edit&columnsOnly=' . implode(',', $this->fieldArray) . '&disHelp=1';
809 $icon .= '<a href="#" onclick="' . htmlspecialchars(\TYPO3\CMS\Backend\Utility\BackendUtility::editOnClick($params, $this->backPath, -1)) . '" title="' . $GLOBALS['LANG']->getLL('editShownColumns', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-open') . '</a>';
810 }
811 // Add an empty entry, so column count fits again after moving this into $icon
812 $theData[$fCol] = '&nbsp;';
813 }
814 break;
815 case '_AFTERCONTROL_':
816
817 case '_AFTERREF_':
818 // space column
819 $theData[$fCol] = '&nbsp;';
820 break;
821 default:
822 // Regular fields header:
823 $theData[$fCol] = '';
824 if ($this->table && is_array($currentIdList)) {
825 // If the numeric clipboard pads are selected, show duplicate sorting link:
826 if ($this->clipNumPane()) {
827 $theData[$fCol] .= '<a href="' . htmlspecialchars(($this->listURL('', -1) . '&duplicateField=' . $fCol)) . '" title="' . $GLOBALS['LANG']->getLL('clip_duplicates', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-duplicates-select') . '</a>';
828 }
829 // If the table can be edited, add link for editing THIS field for all listed records:
830 if (!$GLOBALS['TCA'][$table]['ctrl']['readOnly'] && $permsEdit && $GLOBALS['TCA'][$table]['columns'][$fCol]) {
831 $editIdList = implode(',', $currentIdList);
832 if ($this->clipNumPane()) {
833 $editIdList = '\'+editList(\'' . $table . '\',\'' . $editIdList . '\')+\'';
834 }
835 $params = '&edit[' . $table . '][' . $editIdList . ']=edit&columnsOnly=' . $fCol . '&disHelp=1';
836 $iTitle = sprintf($GLOBALS['LANG']->getLL('editThisColumn'), rtrim(trim($GLOBALS['LANG']->sL(\TYPO3\CMS\Backend\Utility\BackendUtility::getItemLabel($table, $fCol))), ':'));
837 $theData[$fCol] .= '<a href="#" onclick="' . htmlspecialchars(\TYPO3\CMS\Backend\Utility\BackendUtility::editOnClick($params, $this->backPath, -1)) . '" title="' . htmlspecialchars($iTitle) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-open') . '</a>';
838 }
839 }
840 $theData[$fCol] .= $this->addSortLink($GLOBALS['LANG']->sL(\TYPO3\CMS\Backend\Utility\BackendUtility::getItemLabel($table, $fCol, '<i>[|]</i>')), $fCol, $table);
841 break;
842 }
843 }
844 /**
845 * @hook renderListHeader: Allows to change the contents of columns/cells of the Web>List table headers
846 * @date 2007-11-20
847 * @request Bernhard Kraft <krafbt@kraftb.at>
848 * @usage Above each listed table in Web>List a header row is shown. Containing the labels of all shown fields and additional icons to create new records for this table or perform special clipboard tasks like mark and copy all listed records to clipboard, etc.
849 */
850 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['actions'])) {
851 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['actions'] as $classData) {
852 $hookObject = \TYPO3\CMS\Core\Utility\GeneralUtility::getUserObj($classData);
853 if (!$hookObject instanceof \TYPO3\CMS\Recordlist\RecordList\RecordListHookInterface) {
854 throw new \UnexpectedValueException('$hookObject must implement interface TYPO3\\CMS\\Recordlist\\RecordList\\RecordListHookInterface', 1195567855);
855 }
856 $theData = $hookObject->renderListHeader($table, $currentIdList, $theData, $this);
857 }
858 }
859 // Create and return header table row:
860 return $this->addelement(1, $icon, $theData, ' class="c-headLine"', '');
861 }
862
863 /**
864 * Creates a page browser for tables with many records
865 *
866 * @param string $renderPart Distinguish between 'top' and 'bottom' part of the navigation (above or below the records)
867 * @return string Navigation HTML
868 */
869 protected function renderListNavigation($renderPart = 'top') {
870 $totalPages = ceil($this->totalItems / $this->iLimit);
871 $content = '';
872 $returnContent = '';
873 // Show page selector if not all records fit into one page
874 if ($totalPages > 1) {
875 $first = ($previous = ($next = ($last = ($reload = ''))));
876 $listURL = $this->listURL('', $this->table);
877 // 1 = first page
878 $currentPage = floor(($this->firstElementNumber + 1) / $this->iLimit) + 1;
879 // Compile first, previous, next, last and refresh buttons
880 if ($currentPage > 1) {
881 $labelFirst = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:first');
882 $first = '<a href="' . $listURL . '&pointer=0">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-view-paging-first', array('title' => $labelFirst)) . '</a>';
883 } else {
884 $first = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-view-paging-first-disabled');
885 }
886 if ($currentPage - 1 > 0) {
887 $labelPrevious = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:previous');
888 $previous = '<a href="' . $listURL . '&pointer=' . ($currentPage - 2) * $this->iLimit . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-view-paging-previous', array('title' => $labelPrevious)) . '</a>';
889 } else {
890 $previous = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-view-paging-previous-disabled');
891 }
892 if ($currentPage + 1 <= $totalPages) {
893 $labelNext = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:next');
894 $next = '<a href="' . $listURL . '&pointer=' . $currentPage * $this->iLimit . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-view-paging-next', array('title' => $labelNext)) . '</a>';
895 } else {
896 $next = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-view-paging-next-disabled');
897 }
898 if ($currentPage != $totalPages) {
899 $labelLast = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:last');
900 $last = '<a href="' . $listURL . '&pointer=' . ($totalPages - 1) * $this->iLimit . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-view-paging-last', array('title' => $labelLast)) . '</a>';
901 } else {
902 $last = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-view-paging-last-disabled');
903 }
904 $reload = '<a href="#" onclick="document.dblistForm.action=\'' . $listURL . '&pointer=\'+calculatePointer(document.getElementById(\'jumpPage-' . $renderPart . '\').value); document.dblistForm.submit(); return true;" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:reload', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-system-refresh') . '</a>';
905 if ($renderPart === 'top') {
906 // Add js to traverse a page select input to a pointer value
907 $content = '
908 <script type="text/JavaScript">
909 /*<![CDATA[*/
910
911 function calculatePointer(page) {
912 if (page > ' . $totalPages . ') {
913 page = ' . $totalPages . ';
914 }
915
916 if (page < 1) {
917 page = 1;
918 }
919
920 pointer = (page - 1) * ' . $this->iLimit . ';
921
922 return pointer;
923 }
924
925 /*]]>*/
926 </script>
927 ';
928 }
929 $pageNumberInput = '<span>
930 <input type="text" value="' . $currentPage . '" size="3" id="jumpPage-' . $renderPart . '" name="jumpPage-' . $renderPart . '" onkeyup="if (event.keyCode == Event.KEY_RETURN) { document.dblistForm.action=\'' . $listURL . '&pointer=\'+calculatePointer(this.value); document.dblistForm.submit(); } return true;" />
931 </span>';
932 $pageIndicator = '<span class="pageIndicator">' . sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_web_list.xml:pageIndicator'), $pageNumberInput, $totalPages) . '</span>';
933 if ($this->totalItems > $this->firstElementNumber + $this->iLimit) {
934 $lastElementNumber = $this->firstElementNumber + $this->iLimit;
935 } else {
936 $lastElementNumber = $this->totalItems;
937 }
938 $rangeIndicator = '<span class="pageIndicator">' . sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_web_list.xml:rangeIndicator'), ($this->firstElementNumber + 1), $lastElementNumber) . '</span>';
939 $content .= '<div id="typo3-dblist-pagination">' . $first . $previous . '<span class="bar">&nbsp;</span>' . $rangeIndicator . '<span class="bar">&nbsp;</span>' . $pageIndicator . '<span class="bar">&nbsp;</span>' . $next . $last . '<span class="bar">&nbsp;</span>' . $reload . '</div>';
940 $data = array();
941 $titleColumn = $this->fieldArray[0];
942 $data[$titleColumn] = $content;
943 $returnContent = $this->addElement(1, '', $data);
944 }
945 // end of if pages > 1
946 return $returnContent;
947 }
948
949 /*********************************
950 *
951 * Rendering of various elements
952 *
953 *********************************/
954 /**
955 * Creates the control panel for a single record in the listing.
956 *
957 * @param string $table The table
958 * @param array $row The record for which to make the control panel.
959 * @return string HTML table with the control panel (unless disabled)
960 * @todo Define visibility
961 */
962 public function makeControl($table, $row) {
963 if ($this->dontShowClipControlPanels) {
964 return '';
965 }
966 $rowUid = $row['uid'];
967 if (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('version') && isset($row['_ORIG_uid'])) {
968 $rowUid = $row['_ORIG_uid'];
969 }
970 $cells = array();
971 // If the listed table is 'pages' we have to request the permission settings for each page:
972 if ($table == 'pages') {
973 $localCalcPerms = $GLOBALS['BE_USER']->calcPerms(\TYPO3\CMS\Backend\Utility\BackendUtility::getRecord('pages', $row['uid']));
974 }
975 // This expresses the edit permissions for this particular element:
976 $permsEdit = $table == 'pages' && $localCalcPerms & 2 || $table != 'pages' && $this->calcPerms & 16;
977 // "Show" link (only pages and tt_content elements)
978 if ($table == 'pages' || $table == 'tt_content') {
979 $params = '&edit[' . $table . '][' . $row['uid'] . ']=edit';
980 $cells['view'] = '<a href="#" onclick="' . htmlspecialchars(\TYPO3\CMS\Backend\Utility\BackendUtility::viewOnClick(($table == 'tt_content' ? $this->id . '#' . $row['uid'] : $row['uid']), $this->backPath)) . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.showPage', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-view') . '</a>';
981 } elseif (!$this->table) {
982 $cells['view'] = $this->spaceIcon;
983 }
984 // "Edit" link: ( Only if permissions to edit the page-record of the content of the parent page ($this->id)
985 if ($permsEdit) {
986 $params = '&edit[' . $table . '][' . $row['uid'] . ']=edit';
987 $cells['edit'] = '<a href="#" onclick="' . htmlspecialchars(\TYPO3\CMS\Backend\Utility\BackendUtility::editOnClick($params, $this->backPath, -1)) . '" title="' . $GLOBALS['LANG']->getLL('edit', TRUE) . '">' . ($GLOBALS['TCA'][$table]['ctrl']['readOnly'] ? \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-open-read-only') : \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-open')) . '</a>';
988 } elseif (!$this->table) {
989 $cells['edit'] = $this->spaceIcon;
990 }
991 // "Move" wizard link for pages/tt_content elements:
992 if ($table == 'tt_content' && $permsEdit || $table == 'pages') {
993 $cells['move'] = '<a href="#" onclick="' . htmlspecialchars(('return jumpExt(\'' . $this->backPath . 'move_el.php?table=' . $table . '&uid=' . $row['uid'] . '\');')) . '" title="' . $GLOBALS['LANG']->getLL(('move_' . ($table == 'tt_content' ? 'record' : 'page')), TRUE) . '">' . ($table == 'tt_content' ? \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-move') : \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-page-move')) . '</a>';
994 } elseif (!$this->table) {
995 $cells['move'] = $this->spaceIcon;
996 }
997 // If the extended control panel is enabled OR if we are seeing a single table:
998 if ($GLOBALS['SOBE']->MOD_SETTINGS['bigControlPanel'] || $this->table) {
999 // "Info": (All records)
1000 $cells['viewBig'] = '<a href="#" onclick="' . htmlspecialchars(('top.launchView(\'' . $table . '\', \'' . $row['uid'] . '\'); return false;')) . '" title="' . $GLOBALS['LANG']->getLL('showInfo', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-info') . '</a>';
1001 // If the table is NOT a read-only table, then show these links:
1002 if (!$GLOBALS['TCA'][$table]['ctrl']['readOnly']) {
1003 // "Revert" link (history/undo)
1004 $cells['history'] = '<a href="#" onclick="' . htmlspecialchars(('return jumpExt(\'' . $this->backPath . 'show_rechis.php?element=' . rawurlencode(($table . ':' . $row['uid'])) . '\',\'#latest\');')) . '" title="' . $GLOBALS['LANG']->getLL('history', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-history-open') . '</a>';
1005 // Versioning:
1006 if (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('version') && !\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('workspaces')) {
1007 $vers = \TYPO3\CMS\Backend\Utility\BackendUtility::selectVersionsOfRecord($table, $row['uid'], 'uid', $GLOBALS['BE_USER']->workspace, FALSE, $row);
1008 // If table can be versionized.
1009 if (is_array($vers)) {
1010 $versionIcon = 'no-version';
1011 if (count($vers) > 1) {
1012 $versionIcon = count($vers) - 1;
1013 }
1014 $cells['version'] = '<a href="' . htmlspecialchars(($this->backPath . \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath('version') . 'cm1/index.php?table=' . rawurlencode($table) . '&uid=' . rawurlencode($row['uid']))) . '" title="' . $GLOBALS['LANG']->getLL('displayVersions', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon(('status-version-' . $versionIcon)) . '</a>';
1015 } elseif (!$this->table) {
1016 $cells['version'] = $this->spaceIcon;
1017 }
1018 }
1019 // "Edit Perms" link:
1020 if ($table == 'pages' && $GLOBALS['BE_USER']->check('modules', 'web_perm') && \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('perm')) {
1021 $cells['perms'] = '<a href="' . htmlspecialchars((\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath('perm') . 'mod1/index.php' . '?id=' . $row['uid'] . '&return_id=' . $row['uid'] . '&edit=1')) . '" title="' . $GLOBALS['LANG']->getLL('permissions', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('status-status-locked') . '</a>';
1022 } elseif (!$this->table && $GLOBALS['BE_USER']->check('modules', 'web_perm')) {
1023 $cells['perms'] = $this->spaceIcon;
1024 }
1025 // "New record after" link (ONLY if the records in the table are sorted by a "sortby"-row or if default values can depend on previous record):
1026 if ($GLOBALS['TCA'][$table]['ctrl']['sortby'] || $GLOBALS['TCA'][$table]['ctrl']['useColumnsForDefaultValues']) {
1027 if ($table != 'pages' && $this->calcPerms & 16 || $table == 'pages' && $this->calcPerms & 8) {
1028 if ($this->showNewRecLink($table)) {
1029 $params = '&edit[' . $table . '][' . -($row['_MOVE_PLH'] ? $row['_MOVE_PLH_uid'] : $row['uid']) . ']=new';
1030 $cells['new'] = '<a href="#" onclick="' . htmlspecialchars(\TYPO3\CMS\Backend\Utility\BackendUtility::editOnClick($params, $this->backPath, -1)) . '" title="' . $GLOBALS['LANG']->getLL(('new' . ($table == 'pages ' ? 'Page' : 'Record')), TRUE) . '">' . ($table == 'pages' ? \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-page-new') : \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-new')) . '</a>';
1031 }
1032 }
1033 } elseif (!$this->table) {
1034 $cells['new'] = $this->spaceIcon;
1035 }
1036 // "Up/Down" links
1037 if ($permsEdit && $GLOBALS['TCA'][$table]['ctrl']['sortby'] && !$this->sortField && !$this->searchLevels) {
1038 if (isset($this->currentTable['prev'][$row['uid']])) {
1039 // Up
1040 $params = '&cmd[' . $table . '][' . $row['uid'] . '][move]=' . $this->currentTable['prev'][$row['uid']];
1041 $cells['moveUp'] = '<a href="#" onclick="' . htmlspecialchars(('return jumpToUrl(\'' . $GLOBALS['SOBE']->doc->issueCommand($params, -1) . '\');')) . '" title="' . $GLOBALS['LANG']->getLL('moveUp', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-move-up') . '</a>';
1042 } else {
1043 $cells['moveUp'] = $this->spaceIcon;
1044 }
1045 if ($this->currentTable['next'][$row['uid']]) {
1046 // Down
1047 $params = '&cmd[' . $table . '][' . $row['uid'] . '][move]=' . $this->currentTable['next'][$row['uid']];
1048 $cells['moveDown'] = '<a href="#" onclick="' . htmlspecialchars(('return jumpToUrl(\'' . $GLOBALS['SOBE']->doc->issueCommand($params, -1) . '\');')) . '" title="' . $GLOBALS['LANG']->getLL('moveDown', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-move-down') . '</a>';
1049 } else {
1050 $cells['moveDown'] = $this->spaceIcon;
1051 }
1052 } elseif (!$this->table) {
1053 $cells['moveUp'] = $this->spaceIcon;
1054 $cells['moveDown'] = $this->spaceIcon;
1055 }
1056 // "Hide/Unhide" links:
1057 $hiddenField = $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled'];
1058 if ($permsEdit && $hiddenField && $GLOBALS['TCA'][$table]['columns'][$hiddenField] && (!$GLOBALS['TCA'][$table]['columns'][$hiddenField]['exclude'] || $GLOBALS['BE_USER']->check('non_exclude_fields', $table . ':' . $hiddenField))) {
1059 if ($row[$hiddenField]) {
1060 $params = '&data[' . $table . '][' . $rowUid . '][' . $hiddenField . ']=0';
1061 $cells['hide'] = '<a href="#" onclick="' . htmlspecialchars(('return jumpToUrl(\'' . $GLOBALS['SOBE']->doc->issueCommand($params, -1) . '\');')) . '" title="' . $GLOBALS['LANG']->getLL(('unHide' . ($table == 'pages' ? 'Page' : '')), TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-edit-unhide') . '</a>';
1062 } else {
1063 $params = '&data[' . $table . '][' . $rowUid . '][' . $hiddenField . ']=1';
1064 $cells['hide'] = '<a href="#" onclick="' . htmlspecialchars(('return jumpToUrl(\'' . $GLOBALS['SOBE']->doc->issueCommand($params, -1) . '\');')) . '" title="' . $GLOBALS['LANG']->getLL(('hide' . ($table == 'pages' ? 'Page' : '')), TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-edit-hide') . '</a>';
1065 }
1066 } elseif (!$this->table) {
1067 $cells['hide'] = $this->spaceIcon;
1068 }
1069 // "Delete" link:
1070 if ($table == 'pages' && $localCalcPerms & 4 || $table != 'pages' && $this->calcPerms & 16) {
1071 $titleOrig = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecordTitle($table, $row, FALSE, TRUE);
1072 $title = \TYPO3\CMS\Core\Utility\GeneralUtility::slashJS(\TYPO3\CMS\Core\Utility\GeneralUtility::fixed_lgd_cs($titleOrig, $this->fixedL), 1);
1073 $params = '&cmd[' . $table . '][' . $row['uid'] . '][delete]=1';
1074 $refCountMsg = \TYPO3\CMS\Backend\Utility\BackendUtility::referenceCount($table, $row['uid'], (' ' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:labels.referencesToRecord')), $this->getReferenceCount($table, $row['uid'])) . \TYPO3\CMS\Backend\Utility\BackendUtility::translationCount($table, $row['uid'], (' ' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:labels.translationsOfRecord')));
1075 $cells['delete'] = '<a href="#" onclick="' . htmlspecialchars(('if (confirm(' . $GLOBALS['LANG']->JScharCode(($GLOBALS['LANG']->getLL('deleteWarning') . ' "' . $title . '" ' . $refCountMsg)) . ')) {jumpToUrl(\'' . $GLOBALS['SOBE']->doc->issueCommand($params, -1) . '\');} return false;')) . '" title="' . $GLOBALS['LANG']->getLL('delete', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-edit-delete') . '</a>';
1076 } elseif (!$this->table) {
1077 $cells['delete'] = $this->spaceIcon;
1078 }
1079 // "Levels" links: Moving pages into new levels...
1080 if ($permsEdit && $table == 'pages' && !$this->searchLevels) {
1081 // Up (Paste as the page right after the current parent page)
1082 if ($this->calcPerms & 8) {
1083 $params = '&cmd[' . $table . '][' . $row['uid'] . '][move]=' . -$this->id;
1084 $cells['moveLeft'] = '<a href="#" onclick="' . htmlspecialchars(('return jumpToUrl(\'' . $GLOBALS['SOBE']->doc->issueCommand($params, -1) . '\');')) . '" title="' . $GLOBALS['LANG']->getLL('prevLevel', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-move-left') . '</a>';
1085 }
1086 // Down (Paste as subpage to the page right above)
1087 if ($this->currentTable['prevUid'][$row['uid']]) {
1088 $localCalcPerms = $GLOBALS['BE_USER']->calcPerms(\TYPO3\CMS\Backend\Utility\BackendUtility::getRecord('pages', $this->currentTable['prevUid'][$row['uid']]));
1089 if ($localCalcPerms & 8) {
1090 $params = '&cmd[' . $table . '][' . $row['uid'] . '][move]=' . $this->currentTable['prevUid'][$row['uid']];
1091 $cells['moveRight'] = '<a href="#" onclick="' . htmlspecialchars(('return jumpToUrl(\'' . $GLOBALS['SOBE']->doc->issueCommand($params, -1) . '\');')) . '" title="' . $GLOBALS['LANG']->getLL('nextLevel', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-move-right') . '</a>';
1092 } else {
1093 $cells['moveRight'] = $this->spaceIcon;
1094 }
1095 } else {
1096 $cells['moveRight'] = $this->spaceIcon;
1097 }
1098 } elseif (!$this->table) {
1099 $cells['moveLeft'] = $this->spaceIcon;
1100 $cells['moveRight'] = $this->spaceIcon;
1101 }
1102 }
1103 }
1104 /**
1105 * @hook recStatInfoHooks: Allows to insert HTML before record icons on various places
1106 * @date 2007-09-22
1107 * @request Kasper Skårhøj <kasper2007@typo3.com>
1108 */
1109 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['recStatInfoHooks'])) {
1110 $stat = '';
1111 $_params = array($table, $row['uid']);
1112 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['recStatInfoHooks'] as $_funcRef) {
1113 $stat .= \TYPO3\CMS\Core\Utility\GeneralUtility::callUserFunction($_funcRef, $_params, $this);
1114 }
1115 $cells['stat'] = $stat;
1116 }
1117 /**
1118 * @hook makeControl: Allows to change control icons of records in list-module
1119 * @date 2007-11-20
1120 * @request Bernhard Kraft <krafbt@kraftb.at>
1121 * @usage This hook method gets passed the current $cells array as third parameter. This array contains values for the icons/actions generated for each record in Web>List. Each array entry is accessible by an index-key. The order of the icons is dependend on the order of those array entries.
1122 */
1123 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['actions'])) {
1124 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['actions'] as $classData) {
1125 $hookObject = \TYPO3\CMS\Core\Utility\GeneralUtility::getUserObj($classData);
1126 if (!$hookObject instanceof \TYPO3\CMS\Recordlist\RecordList\RecordListHookInterface) {
1127 throw new \UnexpectedValueException('$hookObject must implement interface TYPO3\\CMS\\Recordlist\\RecordList\\RecordListHookInterface', 1195567840);
1128 }
1129 $cells = $hookObject->makeControl($table, $row, $cells, $this);
1130 }
1131 }
1132 // Compile items into a DIV-element:
1133 return '
1134 <!-- CONTROL PANEL: ' . $table . ':' . $row['uid'] . ' -->
1135 <div class="typo3-DBctrl">' . implode('', $cells) . '</div>';
1136 }
1137
1138 /**
1139 * Creates the clipboard panel for a single record in the listing.
1140 *
1141 * @param string $table The table
1142 * @param array $row The record for which to make the clipboard panel.
1143 * @return string HTML table with the clipboard panel (unless disabled)
1144 * @todo Define visibility
1145 */
1146 public function makeClip($table, $row) {
1147 // Return blank, if disabled:
1148 if ($this->dontShowClipControlPanels) {
1149 return '';
1150 }
1151 $cells = array();
1152 $cells['pasteAfter'] = ($cells['pasteInto'] = $this->spaceIcon);
1153 //enables to hide the copy, cut and paste icons for localized records - doesn't make much sense to perform these options for them
1154 $isL10nOverlay = $this->localizationView && $table != 'pages_language_overlay' && $row[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']] != 0;
1155 // Return blank, if disabled:
1156 // Whether a numeric clipboard pad is active or the normal pad we will see different content of the panel:
1157 // For the "Normal" pad:
1158 if ($this->clipObj->current == 'normal') {
1159 // Show copy/cut icons:
1160 $isSel = (string) $this->clipObj->isSelected($table, $row['uid']);
1161 $cells['copy'] = $isL10nOverlay ? $this->spaceIcon : '<a href="#" onclick="' . htmlspecialchars(('return jumpSelf(\'' . $this->clipObj->selUrlDB($table, $row['uid'], 1, ($isSel == 'copy'), array('returnUrl' => '')) . '\');')) . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:cm.copy', TRUE) . '">' . (!$isSel == 'copy' ? \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-edit-copy') : \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-edit-copy-release')) . '</a>';
1162 $cells['cut'] = $isL10nOverlay ? $this->spaceIcon : '<a href="#" onclick="' . htmlspecialchars(('return jumpSelf(\'' . $this->clipObj->selUrlDB($table, $row['uid'], 0, ($isSel == 'cut'), array('returnUrl' => '')) . '\');')) . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:cm.cut', TRUE) . '">' . (!$isSel == 'cut' ? \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-edit-cut') : \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-edit-cut-release')) . '</a>';
1163 } else {
1164 // For the numeric clipboard pads (showing checkboxes where one can select elements on/off)
1165 // Setting name of the element in ->CBnames array:
1166 $n = $table . '|' . $row['uid'];
1167 $this->CBnames[] = $n;
1168 // Check if the current element is selected and if so, prepare to set the checkbox as selected:
1169 $checked = $this->clipObj->isSelected($table, $row['uid']) ? ' checked="checked"' : '';
1170 // If the "duplicateField" value is set then select all elements which are duplicates...
1171 if ($this->duplicateField && isset($row[$this->duplicateField])) {
1172 $checked = '';
1173 if (in_array($row[$this->duplicateField], $this->duplicateStack)) {
1174 $checked = ' checked="checked"';
1175 }
1176 $this->duplicateStack[] = $row[$this->duplicateField];
1177 }
1178 // Adding the checkbox to the panel:
1179 $cells['select'] = $isL10nOverlay ? $this->spaceIcon : '<input type="hidden" name="CBH[' . $n . ']" value="0" /><input type="checkbox" name="CBC[' . $n . ']" value="1" class="smallCheckboxes"' . $checked . ' />';
1180 }
1181 // Now, looking for selected elements from the current table:
1182 $elFromTable = $this->clipObj->elFromTable($table);
1183 if (count($elFromTable) && $GLOBALS['TCA'][$table]['ctrl']['sortby']) {
1184 // IF elements are found and they can be individually ordered, then add a "paste after" icon:
1185 $cells['pasteAfter'] = $isL10nOverlay ? $this->spaceIcon : '<a href="' . htmlspecialchars($this->clipObj->pasteUrl($table, -$row['uid'])) . '" onclick="' . htmlspecialchars(('return ' . $this->clipObj->confirmMsg($table, $row, 'after', $elFromTable))) . '" title="' . $GLOBALS['LANG']->getLL('clip_pasteAfter', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-paste-after') . '</a>';
1186 }
1187 // Now, looking for elements in general:
1188 $elFromTable = $this->clipObj->elFromTable('');
1189 if ($table == 'pages' && count($elFromTable)) {
1190 $cells['pasteInto'] = '<a href="' . htmlspecialchars($this->clipObj->pasteUrl('', $row['uid'])) . '" onclick="' . htmlspecialchars(('return ' . $this->clipObj->confirmMsg($table, $row, 'into', $elFromTable))) . '" title="' . $GLOBALS['LANG']->getLL('clip_pasteInto', TRUE) . '">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-paste-into') . '</a>';
1191 }
1192 /**
1193 * @hook makeClip: Allows to change clip-icons of records in list-module
1194 * @date 2007-11-20
1195 * @request Bernhard Kraft <krafbt@kraftb.at>
1196 * @usage This hook method gets passed the current $cells array as third parameter. This array contains values for the clipboard icons generated for each record in Web>List. Each array entry is accessible by an index-key. The order of the icons is dependend on the order of those array entries.
1197 */
1198 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['actions'])) {
1199 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['actions'] as $classData) {
1200 $hookObject = \TYPO3\CMS\Core\Utility\GeneralUtility::getUserObj($classData);
1201 if (!$hookObject instanceof \TYPO3\CMS\Recordlist\RecordList\RecordListHookInterface) {
1202 throw new \UnexpectedValueException('$hookObject must implement interface TYPO3\\CMS\\Recordlist\\RecordList\\RecordListHookInterface', 1195567845);
1203 }
1204 $cells = $hookObject->makeClip($table, $row, $cells, $this);
1205 }
1206 }
1207 // Compile items into a DIV-element:
1208 return ' <!-- CLIPBOARD PANEL: ' . $table . ':' . $row['uid'] . ' -->
1209 <div class="typo3-clipCtrl">' . implode('', $cells) . '</div>';
1210 }
1211
1212 /**
1213 * Creates the HTML for a reference count for the record with the UID $uid
1214 * in the table $tableName.
1215 *
1216 * @param string $tableName
1217 * @param integer $uid
1218 * @return string HTML of reference a link, will be empty if there are no
1219 */
1220 protected function createReferenceHtml($tableName, $uid) {
1221 $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('tablename, recuid, field', 'sys_refindex', 'ref_table = ' . $GLOBALS['TYPO3_DB']->fullQuoteStr($tableName, 'sys_refindex') . ' AND ref_uid = ' . $uid . ' AND deleted = 0', '', '', '0,20');
1222 return $this->generateReferenceToolTip($rows, '\'' . $tableName . '\', \'' . $uid . '\'');
1223 }
1224
1225 /**
1226 * Creates the localization panel
1227 *
1228 * @param string $table The table
1229 * @param array $row The record for which to make the localization panel.
1230 * @return array Array with key 0/1 with content for column 1 and 2
1231 * @todo Define visibility
1232 */
1233 public function makeLocalizationPanel($table, $row) {
1234 $out = array(
1235 0 => '',
1236 1 => ''
1237 );
1238 $translations = $this->translateTools->translationInfo($table, $row['uid'], 0, $row, $this->selFieldList);
1239 $this->translations = $translations['translations'];
1240 // Language title and icon:
1241 $out[0] = $this->languageFlag($row[$GLOBALS['TCA'][$table]['ctrl']['languageField']]);
1242 if (is_array($translations)) {
1243 // Traverse page translations and add icon for each language that does NOT yet exist:
1244 $lNew = '';
1245 foreach ($this->pageOverlays as $lUid_OnPage => $lsysRec) {
1246 if (!isset($translations['translations'][$lUid_OnPage]) && $GLOBALS['BE_USER']->checkLanguageAccess($lUid_OnPage)) {
1247 $url = substr($this->listURL(), strlen($this->backPath));
1248 $href = $GLOBALS['SOBE']->doc->issueCommand('&cmd[' . $table . '][' . $row['uid'] . '][localize]=' . $lUid_OnPage, $url . '&justLocalized=' . rawurlencode(($table . ':' . $row['uid'] . ':' . $lUid_OnPage)));
1249 $language = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord('sys_language', $lUid_OnPage, 'title');
1250 if ($this->languageIconTitles[$lUid_OnPage]['flagIcon']) {
1251 $lC = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon($this->languageIconTitles[$lUid_OnPage]['flagIcon']);
1252 } else {
1253 $lC = $this->languageIconTitles[$lUid_OnPage]['title'];
1254 }
1255 $lC = '<a href="' . htmlspecialchars($href) . '" title="' . htmlspecialchars($language['title']) . '">' . $lC . '</a> ';
1256 $lNew .= $lC;
1257 }
1258 }
1259 if ($lNew) {
1260 $out[1] .= $lNew;
1261 }
1262 } elseif ($row['l18n_parent']) {
1263 $out[0] = '&nbsp;&nbsp;&nbsp;&nbsp;' . $out[0];
1264 }
1265 return $out;
1266 }
1267
1268 /**
1269 * Create the selector box for selecting fields to display from a table:
1270 *
1271 * @param string $table Table name
1272 * @param boolean $formFields If TRUE, form-fields will be wrapped around the table.
1273 * @return string HTML table with the selector box (name: displayFields['.$table.'][])
1274 * @todo Define visibility
1275 */
1276 public function fieldSelectBox($table, $formFields = 1) {
1277 // Init:
1278 $formElements = array('', '');
1279 if ($formFields) {
1280 $formElements = array('<form action="' . htmlspecialchars($this->listURL()) . '" method="post">', '</form>');
1281 }
1282 // Load already selected fields, if any:
1283 $setFields = is_array($this->setFields[$table]) ? $this->setFields[$table] : array();
1284 // Request fields from table:
1285 $fields = $this->makeFieldList($table, FALSE, TRUE);
1286 // Add pseudo "control" fields
1287 $fields[] = '_PATH_';
1288 $fields[] = '_REF_';
1289 $fields[] = '_LOCALIZATION_';
1290 $fields[] = '_CONTROL_';
1291 $fields[] = '_CLIPBOARD_';
1292 // Create an option for each field:
1293 $opt = array();
1294 $opt[] = '<option value=""></option>';
1295 foreach ($fields as $fN) {
1296 // Field label
1297 $fL = is_array($GLOBALS['TCA'][$table]['columns'][$fN]) ? rtrim($GLOBALS['LANG']->sL($GLOBALS['TCA'][$table]['columns'][$fN]['label']), ':') : '[' . $fN . ']';
1298 $opt[] = '
1299 <option value="' . $fN . '"' . (in_array($fN, $setFields) ? ' selected="selected"' : '') . '>' . htmlspecialchars($fL) . '</option>';
1300 }
1301 // Compile the options into a multiple selector box:
1302 $lMenu = '
1303 <select size="' . \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange((count($fields) + 1), 3, 20) . '" multiple="multiple" name="displayFields[' . $table . '][]">' . implode('', $opt) . '
1304 </select>
1305 ';
1306 // Table with the field selector::
1307 $content = $formElements[0] . '
1308
1309 <!--
1310 Field selector for extended table view:
1311 -->
1312 <table border="0" cellpadding="0" cellspacing="0" id="typo3-dblist-fieldSelect">
1313 <tr>
1314 <td>' . $lMenu . '</td>
1315 <td><input type="submit" name="search" value="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.setFields', 1) . '" /></td>
1316 </tr>
1317 </table>
1318 ' . $formElements[1];
1319 return '<div class="db_list-fieldSelect">' . $content . '</div>';
1320 }
1321
1322 /*********************************
1323 *
1324 * Helper functions
1325 *
1326 *********************************/
1327 /**
1328 * Creates a link around $string. The link contains an onclick action which submits the script with some clipboard action.
1329 * Currently, this is used for setting elements / delete elements.
1330 *
1331 * @param string $string The HTML content to link (image/text)
1332 * @param string $table Table name
1333 * @param string $cmd Clipboard command (eg. "setCB" or "delete")
1334 * @param string $warning Warning text, if any ("delete" uses this for confirmation)
1335 * @return string <a> tag wrapped link.
1336 * @todo Define visibility
1337 */
1338 public function linkClipboardHeaderIcon($string, $table, $cmd, $warning = '') {
1339 $onClickEvent = 'document.dblistForm.cmd.value=\'' . $cmd . '\';document.dblistForm.cmd_table.value=\'' . $table . '\';document.dblistForm.submit();';
1340 if ($warning) {
1341 $onClickEvent = 'if (confirm(' . $GLOBALS['LANG']->JScharCode($warning) . ')){' . $onClickEvent . '}';
1342 }
1343 return '<a href="#" onclick="' . htmlspecialchars(($onClickEvent . 'return false;')) . '">' . $string . '</a>';
1344 }
1345
1346 /**
1347 * Returns TRUE if a numeric clipboard pad is selected/active
1348 *
1349 * @return boolean
1350 * @todo Define visibility
1351 */
1352 public function clipNumPane() {
1353 return in_Array('_CLIPBOARD_', $this->fieldArray) && $this->clipObj->current != 'normal';
1354 }
1355
1356 /**
1357 * Creates a sort-by link on the input string ($code).
1358 * It will automatically detect if sorting should be ascending or descending depending on $this->sortRev.
1359 * Also some fields will not be possible to sort (including if single-table-view is disabled).
1360 *
1361 * @param string $code The string to link (text)
1362 * @param string $field The fieldname represented by the title ($code)
1363 * @param string $table Table name
1364 * @return string Linked $code variable
1365 * @todo Define visibility
1366 */
1367 public function addSortLink($code, $field, $table) {
1368 // Certain circumstances just return string right away (no links):
1369 if ($field == '_CONTROL_' || $field == '_LOCALIZATION_' || $field == '_CLIPBOARD_' || $field == '_REF_' || $this->disableSingleTableView) {
1370 return $code;
1371 }
1372 // If "_PATH_" (showing record path) is selected, force sorting by pid field (will at least group the records!)
1373 if ($field == '_PATH_') {
1374 $field = 'pid';
1375 }
1376 // Create the sort link:
1377 $sortUrl = $this->listURL('', -1, 'sortField,sortRev,table,firstElementNumber') . '&table=' . $table . '&sortField=' . $field . '&sortRev=' . ($this->sortRev || $this->sortField != $field ? 0 : 1);
1378 $sortArrow = $this->sortField === $field ? \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('status-status-sorting-' . ($this->sortRev ? 'desc' : 'asc')) : '';
1379 // Return linked field:
1380 return '<a href="' . htmlspecialchars($sortUrl) . '">' . $code . $sortArrow . '</a>';
1381 }
1382
1383 /**
1384 * Returns the path for a certain pid
1385 * The result is cached internally for the session, thus you can call this function as much as you like without performance problems.
1386 *
1387 * @param integer $pid The page id for which to get the path
1388 * @return string The path.
1389 * @todo Define visibility
1390 */
1391 public function recPath($pid) {
1392 if (!isset($this->recPath_cache[$pid])) {
1393 $this->recPath_cache[$pid] = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecordPath($pid, $this->perms_clause, 20);
1394 }
1395 return $this->recPath_cache[$pid];
1396 }
1397
1398 /**
1399 * Returns TRUE if a link for creating new records should be displayed for $table
1400 *
1401 * @param string $table Table name
1402 * @return boolean Returns TRUE if a link for creating new records should be displayed for $table
1403 * @see SC_db_new::showNewRecLink
1404 * @todo Define visibility
1405 */
1406 public function showNewRecLink($table) {
1407 // No deny/allow tables are set:
1408 if (!count($this->allowedNewTables) && !count($this->deniedNewTables)) {
1409 return TRUE;
1410 } elseif (!in_array($table, $this->deniedNewTables) && (!count($this->allowedNewTables) || in_array($table, $this->allowedNewTables))) {
1411 return TRUE;
1412 } else {
1413 return FALSE;
1414 }
1415 }
1416
1417 /**
1418 * Creates the "&returnUrl" parameter for links - this is used when the script links to other scripts and passes its own URL with the link so other scripts can return to the listing again.
1419 * Uses REQUEST_URI as value.
1420 *
1421 * @return string
1422 * @todo Define visibility
1423 */
1424 public function makeReturnUrl() {
1425 return '&returnUrl=' . rawurlencode(\TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('REQUEST_URI'));
1426 }
1427
1428 /************************************
1429 *
1430 * CSV related functions
1431 *
1432 ************************************/
1433 /**
1434 * Initializes internal csvLines array with the header of field names
1435 *
1436 * @return void
1437 */
1438 protected function initCSV() {
1439 $this->addHeaderRowToCSV();
1440 }
1441
1442 /**
1443 * Add header line with field names as CSV line
1444 *
1445 * @return void
1446 */
1447 protected function addHeaderRowToCSV() {
1448 // Add header row, control fields will be reduced inside addToCSV()
1449 $this->addToCSV(array_combine($this->fieldArray, $this->fieldArray));
1450 }
1451
1452 /**
1453 * Adds selected columns of one table row as CSV line.
1454 *
1455 * @param array $row Record array, from which the values of fields found in $this->fieldArray will be listed in the CSV output.
1456 * @return void
1457 */
1458 protected function addToCSV(array $row = array()) {
1459 $rowReducedByControlFields = self::removeControlFieldsFromFieldRow($row);
1460 $rowReducedToSelectedColumns = array_intersect_key($rowReducedByControlFields, array_flip($this->fieldArray));
1461 $this->setCsvRow($rowReducedToSelectedColumns);
1462 }
1463
1464 /**
1465 * Remove control fields from row for CSV export
1466 *
1467 * @param array $row fieldNames => fieldValues
1468 * @return array Input array reduces by control fields
1469 */
1470 static protected function removeControlFieldsFromFieldRow(array $row = array()) {
1471 // Possible control fields in a list row
1472 $controlFields = array(
1473 '_PATH_',
1474 '_REF_',
1475 '_CONTROL_',
1476 '_AFTERCONTROL_',
1477 '_AFTERREF_',
1478 '_CLIPBOARD_',
1479 '_LOCALIZATION_',
1480 '_LOCALIZATION_b'
1481 );
1482 return array_diff_key($row, array_flip($controlFields));
1483 }
1484
1485 /**
1486 * Adds input row of values to the internal csvLines array as a CSV formatted line
1487 *
1488 * @param array $csvRow Array with values to be listed.
1489 * @return void
1490 * @todo Define visibility
1491 */
1492 public function setCsvRow($csvRow) {
1493 $this->csvLines[] = \TYPO3\CMS\Core\Utility\GeneralUtility::csvValues($csvRow);
1494 }
1495
1496 /**
1497 * Compiles the internal csvLines array to a csv-string and outputs it to the browser.
1498 * This function exits!
1499 *
1500 * @param string $prefix Filename prefix:
1501 * @return void EXITS php execusion!
1502 * @todo Define visibility
1503 */
1504 public function outputCSV($prefix) {
1505 // Setting filename:
1506 $filename = $prefix . '_' . date('dmy-Hi') . '.csv';
1507 // Creating output header:
1508 $mimeType = 'application/octet-stream';
1509 header('Content-Type: ' . $mimeType);
1510 header('Content-Disposition: attachment; filename=' . $filename);
1511 // Printing the content of the CSV lines:
1512 echo implode(chr(13) . chr(10), $this->csvLines);
1513 // Exits:
1514 die;
1515 }
1516
1517 }
1518
1519
1520 ?>