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