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