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