[TASK] Respect editlock of pages in inline editing
[Packages/TYPO3.CMS.git] / typo3 / sysext / recordlist / Classes / RecordList.php
1 <?php
2 namespace TYPO3\CMS\Recordlist;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Backend\Clipboard\Clipboard;
18 use TYPO3\CMS\Backend\Template\DocumentTemplate;
19 use TYPO3\CMS\Backend\Utility\BackendUtility;
20 use TYPO3\CMS\Backend\Utility\IconUtility;
21 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
22 use TYPO3\CMS\Core\DataHandling\DataHandler;
23 use TYPO3\CMS\Core\Messaging\FlashMessage;
24 use TYPO3\CMS\Core\Page\PageRenderer;
25 use TYPO3\CMS\Core\Type\Bitmask\Permission;
26 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
27 use TYPO3\CMS\Core\Utility\GeneralUtility;
28 use TYPO3\CMS\Core\Utility\MathUtility;
29 use TYPO3\CMS\Extbase\Service\TypoScriptService;
30 use TYPO3\CMS\Lang\LanguageService;
31
32 /**
33 * Script Class for the Web > List module; rendering the listing of records on a page
34 */
35 class RecordList {
36
37 /**
38 * Page Id for which to make the listing
39 *
40 * @var int
41 */
42 public $id;
43
44 /**
45 * Pointer - for browsing list of records.
46 *
47 * @var int
48 */
49 public $pointer;
50
51 /**
52 * Thumbnails or not
53 *
54 * @var string
55 */
56 public $imagemode;
57
58 /**
59 * Which table to make extended listing for
60 *
61 * @var string
62 */
63 public $table;
64
65 /**
66 * Search-fields
67 *
68 * @var string
69 */
70 public $search_field;
71
72 /**
73 * Search-levels
74 *
75 * @var int
76 */
77 public $search_levels;
78
79 /**
80 * Show-limit
81 *
82 * @var int
83 */
84 public $showLimit;
85
86 /**
87 * Return URL
88 *
89 * @var string
90 */
91 public $returnUrl;
92
93 /**
94 * Clear-cache flag - if set, clears page cache for current id.
95 *
96 * @var bool
97 */
98 public $clear_cache;
99
100 /**
101 * Command: Eg. "delete" or "setCB" (for TCEmain / clipboard operations)
102 *
103 * @var string
104 */
105 public $cmd;
106
107 /**
108 * Table on which the cmd-action is performed.
109 *
110 * @var string
111 */
112 public $cmd_table;
113
114 /**
115 * Page select perms clause
116 *
117 * @var int
118 */
119 public $perms_clause;
120
121 /**
122 * Module TSconfig
123 *
124 * @var array
125 */
126 public $modTSconfig;
127
128 /**
129 * Current ids page record
130 *
131 * @var mixed[]|bool
132 */
133 public $pageinfo;
134
135 /**
136 * Document template object
137 *
138 * @var DocumentTemplate
139 */
140 public $doc;
141
142 /**
143 * Module configuration
144 *
145 * @var array
146 * @deprecated since TYPO3 CMS 7, will be removed in CMS 8.
147 */
148 public $MCONF = array();
149
150 /**
151 * Menu configuration
152 *
153 * @var string[]
154 */
155 public $MOD_MENU = array();
156
157 /**
158 * Module settings (session variable)
159 *
160 * @var string[]
161 */
162 public $MOD_SETTINGS = array();
163
164 /**
165 * Module output accumulation
166 *
167 * @var string
168 */
169 public $content;
170
171 /**
172 * The name of the module
173 *
174 * @var string
175 */
176 protected $moduleName = 'web_list';
177
178 /**
179 * @var string
180 */
181 public $body = '';
182
183 /**
184 * @var PageRenderer
185 */
186 protected $pageRenderer = NULL;
187
188 /**
189 * Constructor
190 */
191 public function __construct() {
192 $this->getLanguageService()->includeLLFile('EXT:lang/locallang_mod_web_list.xlf');
193 $this->pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
194 $this->pageRenderer->loadJquery();
195 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Recordlist/FieldSelectBox');
196 }
197
198 /**
199 * Initializing the module
200 *
201 * @return void
202 */
203 public function init() {
204 $backendUser = $this->getBackendUserAuthentication();
205 $this->perms_clause = $backendUser->getPagePermsClause(1);
206 // Get session data
207 $sessionData = $backendUser->getSessionData(__CLASS__);
208 $this->search_field = !empty($sessionData['search_field']) ? $sessionData['search_field'] : '';
209 // GPvars:
210 $this->id = (int)GeneralUtility::_GP('id');
211 $this->pointer = GeneralUtility::_GP('pointer');
212 $this->imagemode = GeneralUtility::_GP('imagemode');
213 $this->table = GeneralUtility::_GP('table');
214 $this->search_field = GeneralUtility::_GP('search_field');
215 $this->search_levels = (int)GeneralUtility::_GP('search_levels');
216 $this->showLimit = GeneralUtility::_GP('showLimit');
217 $this->returnUrl = GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('returnUrl'));
218 $this->clear_cache = GeneralUtility::_GP('clear_cache');
219 $this->cmd = GeneralUtility::_GP('cmd');
220 $this->cmd_table = GeneralUtility::_GP('cmd_table');
221 $sessionData['search_field'] = $this->search_field;
222 // Initialize menu
223 $this->menuConfig();
224 // Store session data
225 $backendUser->setAndSaveSessionData(RecordList::class, $sessionData);
226 $this->getPageRenderer()->addInlineLanguageLabelFile('EXT:lang/locallang_mod_web_list.xlf');
227 }
228
229 /**
230 * Initialize function menu array
231 *
232 * @return void
233 */
234 public function menuConfig() {
235 // MENU-ITEMS:
236 $this->MOD_MENU = array(
237 'bigControlPanel' => '',
238 'clipBoard' => '',
239 'localization' => ''
240 );
241 // Loading module configuration:
242 $this->modTSconfig = BackendUtility::getModTSconfig($this->id, 'mod.' . $this->moduleName);
243 // Clean up settings:
244 $this->MOD_SETTINGS = BackendUtility::getModuleData($this->MOD_MENU, GeneralUtility::_GP('SET'), $this->moduleName);
245 }
246
247 /**
248 * Clears page cache for the current id, $this->id
249 *
250 * @return void
251 */
252 public function clearCache() {
253 if ($this->clear_cache) {
254 $tce = GeneralUtility::makeInstance(DataHandler::class);
255 $tce->stripslashes_values = 0;
256 $tce->start(array(), array());
257 $tce->clear_cacheCmd($this->id);
258 }
259 }
260
261 /**
262 * Main function, starting the rendering of the list.
263 *
264 * @return void
265 */
266 public function main() {
267 $backendUser = $this->getBackendUserAuthentication();
268 $lang = $this->getLanguageService();
269 // Loading current page record and checking access:
270 $this->pageinfo = BackendUtility::readPageAccess($this->id, $this->perms_clause);
271 $access = is_array($this->pageinfo) ? 1 : 0;
272 // Start document template object:
273 $this->doc = GeneralUtility::makeInstance(DocumentTemplate::class);
274 $this->doc->setModuleTemplate('EXT:recordlist/Resources/Private/Templates/db_list.html');
275 $this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/AjaxDataHandler');
276 $calcPerms = $backendUser->calcPerms($this->pageinfo);
277 $userCanEditPage = $calcPerms & Permission::PAGE_EDIT && !empty($this->id) && ($backendUser->isAdmin() || (int)$this->pageinfo['editlock'] === 0);
278 $this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/PageActions', 'function(PageActions) {
279 PageActions.setPageId(' . (int)$this->id . ');
280 PageActions.setCanEditPage(' . ($userCanEditPage ? 'true' : 'false') . ');
281 PageActions.initializePageTitleRenaming();
282 }');
283 $this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Recordlist/Tooltip');
284 // Apply predefined values for hidden checkboxes
285 // Set predefined value for DisplayBigControlPanel:
286 if ($this->modTSconfig['properties']['enableDisplayBigControlPanel'] === 'activated') {
287 $this->MOD_SETTINGS['bigControlPanel'] = TRUE;
288 } elseif ($this->modTSconfig['properties']['enableDisplayBigControlPanel'] === 'deactivated') {
289 $this->MOD_SETTINGS['bigControlPanel'] = FALSE;
290 }
291 // Set predefined value for Clipboard:
292 if ($this->modTSconfig['properties']['enableClipBoard'] === 'activated') {
293 $this->MOD_SETTINGS['clipBoard'] = TRUE;
294 } elseif ($this->modTSconfig['properties']['enableClipBoard'] === 'deactivated') {
295 $this->MOD_SETTINGS['clipBoard'] = FALSE;
296 } else {
297 if ($this->MOD_SETTINGS['clipBoard'] === NULL) {
298 $this->MOD_SETTINGS['clipBoard'] = TRUE;
299 }
300 }
301 // Set predefined value for LocalizationView:
302 if ($this->modTSconfig['properties']['enableLocalizationView'] === 'activated') {
303 $this->MOD_SETTINGS['localization'] = TRUE;
304 } elseif ($this->modTSconfig['properties']['enableLocalizationView'] === 'deactivated') {
305 $this->MOD_SETTINGS['localization'] = FALSE;
306 }
307
308 // Initialize the dblist object:
309 /** @var $dblist RecordList\DatabaseRecordList */
310 $dblist = GeneralUtility::makeInstance(RecordList\DatabaseRecordList::class);
311 $dblist->script = BackendUtility::getModuleUrl('web_list');
312 $dblist->calcPerms = $calcPerms;
313 $dblist->thumbs = $backendUser->uc['thumbnailsByDefault'];
314 $dblist->returnUrl = $this->returnUrl;
315 $dblist->allFields = $this->MOD_SETTINGS['bigControlPanel'] || $this->table ? 1 : 0;
316 $dblist->localizationView = $this->MOD_SETTINGS['localization'];
317 $dblist->showClipboard = 1;
318 $dblist->disableSingleTableView = $this->modTSconfig['properties']['disableSingleTableView'];
319 $dblist->listOnlyInSingleTableMode = $this->modTSconfig['properties']['listOnlyInSingleTableView'];
320 $dblist->hideTables = $this->modTSconfig['properties']['hideTables'];
321 $dblist->hideTranslations = $this->modTSconfig['properties']['hideTranslations'];
322 $dblist->tableTSconfigOverTCA = $this->modTSconfig['properties']['table.'];
323 $dblist->allowedNewTables = GeneralUtility::trimExplode(',', $this->modTSconfig['properties']['allowedNewTables'], TRUE);
324 $dblist->deniedNewTables = GeneralUtility::trimExplode(',', $this->modTSconfig['properties']['deniedNewTables'], TRUE);
325 $dblist->newWizards = $this->modTSconfig['properties']['newWizards'] ? 1 : 0;
326 $dblist->pageRow = $this->pageinfo;
327 $dblist->counter++;
328 $dblist->MOD_MENU = array('bigControlPanel' => '', 'clipBoard' => '', 'localization' => '');
329 $dblist->modTSconfig = $this->modTSconfig;
330 $clickTitleMode = trim($this->modTSconfig['properties']['clickTitleMode']);
331 $dblist->clickTitleMode = $clickTitleMode === '' ? 'edit' : $clickTitleMode;
332 if (isset($this->modTSconfig['properties']['tableDisplayOrder.'])) {
333 $typoScriptService = GeneralUtility::makeInstance(TypoScriptService::class);
334 $dblist->setTableDisplayOrder($typoScriptService->convertTypoScriptArrayToPlainArray($this->modTSconfig['properties']['tableDisplayOrder.']));
335 }
336 // Clipboard is initialized:
337 // Start clipboard
338 $dblist->clipObj = GeneralUtility::makeInstance(Clipboard::class);
339 // Initialize - reads the clipboard content from the user session
340 $dblist->clipObj->initializeClipboard();
341 // Clipboard actions are handled:
342 // CB is the clipboard command array
343 $CB = GeneralUtility::_GET('CB');
344 if ($this->cmd == 'setCB') {
345 // CBH is all the fields selected for the clipboard, CBC is the checkbox fields which were checked.
346 // By merging we get a full array of checked/unchecked elements
347 // This is set to the 'el' array of the CB after being parsed so only the table in question is registered.
348 $CB['el'] = $dblist->clipObj->cleanUpCBC(array_merge(GeneralUtility::_POST('CBH'), (array)GeneralUtility::_POST('CBC')), $this->cmd_table);
349 }
350 if (!$this->MOD_SETTINGS['clipBoard']) {
351 // If the clipboard is NOT shown, set the pad to 'normal'.
352 $CB['setP'] = 'normal';
353 }
354 // Execute commands.
355 $dblist->clipObj->setCmd($CB);
356 // Clean up pad
357 $dblist->clipObj->cleanCurrent();
358 // Save the clipboard content
359 $dblist->clipObj->endClipboard();
360 // This flag will prevent the clipboard panel in being shown.
361 // It is set, if the clickmenu-layer is active AND the extended view is not enabled.
362 $dblist->dontShowClipControlPanels = ($dblist->clipObj->current == 'normal' && !$this->modTSconfig['properties']['showClipControlPanelsDespiteOfCMlayers']);
363 // If there is access to the page or root page is used for searching, then render the list contents and set up the document template object:
364 if ($access || ($this->id === 0 && $this->search_levels > 0 && $this->search_field !== '')) {
365 // Deleting records...:
366 // Has not to do with the clipboard but is simply the delete action. The clipboard object is used to clean up the submitted entries to only the selected table.
367 if ($this->cmd == 'delete') {
368 $items = $dblist->clipObj->cleanUpCBC(GeneralUtility::_POST('CBC'), $this->cmd_table, 1);
369 if (!empty($items)) {
370 $cmd = array();
371 foreach ($items as $iK => $value) {
372 $iKParts = explode('|', $iK);
373 $cmd[$iKParts[0]][$iKParts[1]]['delete'] = 1;
374 }
375 $tce = GeneralUtility::makeInstance(DataHandler::class);
376 $tce->stripslashes_values = 0;
377 $tce->start(array(), $cmd);
378 $tce->process_cmdmap();
379 if (isset($cmd['pages'])) {
380 BackendUtility::setUpdateSignal('updatePageTree');
381 }
382 $tce->printLogErrorMessages(GeneralUtility::getIndpEnv('REQUEST_URI'));
383 }
384 }
385 // Initialize the listing object, dblist, for rendering the list:
386 $this->pointer = MathUtility::forceIntegerInRange($this->pointer, 0, 100000);
387 $dblist->start($this->id, $this->table, $this->pointer, $this->search_field, $this->search_levels, $this->showLimit);
388 $dblist->setDispFields();
389 // Render versioning selector:
390 if (ExtensionManagementUtility::isLoaded('version')) {
391 $dblist->HTMLcode .= $this->doc->getVersionSelector($this->id);
392 }
393 // Render the list of tables:
394 $dblist->generateList();
395 $listUrl = $dblist->listURL();
396 // Add JavaScript functions to the page:
397 $this->doc->JScode = $this->doc->wrapScriptTags('
398 function jumpExt(URL,anchor) { //
399 var anc = anchor?anchor:"";
400 window.location.href = URL+(T3_THIS_LOCATION?"&returnUrl="+T3_THIS_LOCATION:"")+anc;
401 return false;
402 }
403 function jumpSelf(URL) { //
404 window.location.href = URL+(T3_RETURN_URL?"&returnUrl="+T3_RETURN_URL:"");
405 return false;
406 }
407
408 function setHighlight(id) { //
409 top.fsMod.recentIds["web"]=id;
410 top.fsMod.navFrameHighlightedID["web"]="pages"+id+"_"+top.fsMod.currentBank; // For highlighting
411
412 if (top.content && top.content.nav_frame && top.content.nav_frame.refresh_nav) {
413 top.content.nav_frame.refresh_nav();
414 }
415 }
416 ' . $this->doc->redirectUrls($listUrl) . '
417 ' . $dblist->CBfunctions() . '
418 function editRecords(table,idList,addParams,CBflag) { //
419 window.location.href="' . BackendUtility::getModuleUrl('record_edit', array('returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI'))) . '&edit["+table+"]["+idList+"]=edit"+addParams;
420 }
421 function editList(table,idList) { //
422 var list="";
423
424 // Checking how many is checked, how many is not
425 var pointer=0;
426 var pos = idList.indexOf(",");
427 while (pos!=-1) {
428 if (cbValue(table+"|"+idList.substr(pointer,pos-pointer))) {
429 list+=idList.substr(pointer,pos-pointer)+",";
430 }
431 pointer=pos+1;
432 pos = idList.indexOf(",",pointer);
433 }
434 if (cbValue(table+"|"+idList.substr(pointer))) {
435 list+=idList.substr(pointer)+",";
436 }
437
438 return list ? list : idList;
439 }
440
441 if (top.fsMod) top.fsMod.recentIds["web"] = ' . (int)$this->id . ';
442 ');
443 // Setting up the context sensitive menu:
444 $this->doc->getContextMenuCode();
445 }
446 // access
447 // Begin to compile the whole page, starting out with page header:
448 if (!$this->id) {
449 $this->body = $this->doc->header($GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename']);
450 } else {
451 $this->body = $this->doc->header($this->pageinfo['title']);
452 }
453
454 if (!empty($dblist->HTMLcode)) {
455 $output = $dblist->HTMLcode;
456 } else {
457 $output = $flashMessage = GeneralUtility::makeInstance(
458 FlashMessage::class,
459 $lang->getLL('noRecordsOnThisPage'),
460 '',
461 FlashMessage::INFO
462 )->render();
463 }
464
465 $this->body .= '<form action="' . htmlspecialchars($dblist->listURL()) . '" method="post" name="dblistForm">';
466 $this->body .= $output;
467 $this->body .= '<input type="hidden" name="cmd_table" /><input type="hidden" name="cmd" /></form>';
468 // If a listing was produced, create the page footer with search form etc:
469 if ($dblist->HTMLcode) {
470 // Making field select box (when extended view for a single table is enabled):
471 if ($dblist->table) {
472 $this->body .= $dblist->fieldSelectBox($dblist->table);
473 }
474 // Adding checkbox options for extended listing and clipboard display:
475 $this->body .= '
476
477 <!--
478 Listing options for extended view, clipboard and localization view
479 -->
480 <div class="typo3-listOptions">
481 <form action="" method="post">';
482
483 // Add "display bigControlPanel" checkbox:
484 if ($this->modTSconfig['properties']['enableDisplayBigControlPanel'] === 'selectable') {
485 $this->body .= '<div class="checkbox">' .
486 '<label for="checkLargeControl">' .
487 BackendUtility::getFuncCheck($this->id, 'SET[bigControlPanel]', $this->MOD_SETTINGS['bigControlPanel'], '', $this->table ? '&table=' . $this->table : '', 'id="checkLargeControl"') .
488 BackendUtility::wrapInHelp('xMOD_csh_corebe', 'list_options', $lang->getLL('largeControl', TRUE)) .
489 '</label>' .
490 '</div>';
491 }
492
493 // Add "clipboard" checkbox:
494 if ($this->modTSconfig['properties']['enableClipBoard'] === 'selectable') {
495 if ($dblist->showClipboard) {
496 $this->body .= '<div class="checkbox">' .
497 '<label for="checkShowClipBoard">' .
498 BackendUtility::getFuncCheck($this->id, 'SET[clipBoard]', $this->MOD_SETTINGS['clipBoard'], '', $this->table ? '&table=' . $this->table : '', 'id="checkShowClipBoard"') .
499 BackendUtility::wrapInHelp('xMOD_csh_corebe', 'list_options', $lang->getLL('showClipBoard', TRUE)) .
500 '</label>' .
501 '</div>';
502 }
503 }
504
505 // Add "localization view" checkbox:
506 if ($this->modTSconfig['properties']['enableLocalizationView'] === 'selectable') {
507 $this->body .= '<div class="checkbox">' .
508 '<label for="checkLocalization">' .
509 BackendUtility::getFuncCheck($this->id, 'SET[localization]', $this->MOD_SETTINGS['localization'], '', $this->table ? '&table=' . $this->table : '', 'id="checkLocalization"') .
510 BackendUtility::wrapInHelp('xMOD_csh_corebe', 'list_options', $lang->getLL('localization', TRUE)) .
511 '</label>' .
512 '</div>';
513 }
514
515 $this->body .= '
516 </form>
517 </div>';
518 }
519 // Printing clipboard if enabled
520 if ($this->MOD_SETTINGS['clipBoard'] && $dblist->showClipboard && ($dblist->HTMLcode || $dblist->clipObj->hasElements())) {
521 $this->body .= '<div class="db_list-dashboard">' . $dblist->clipObj->printClipboard() . '</div>';
522 }
523 // Additional footer content
524 $footerContentHook = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['recordlist/Modules/Recordlist/index.php']['drawFooterHook'];
525 if (is_array($footerContentHook)) {
526 foreach ($footerContentHook as $hook) {
527 $params = array();
528 $this->body .= GeneralUtility::callUserFunction($hook, $params, $this);
529 }
530 }
531 // Setting up the buttons and markers for docheader
532 $docHeaderButtons = $dblist->getButtons();
533 $markers = array(
534 'CSH' => $docHeaderButtons['csh'],
535 'CONTENT' => $this->body,
536 'EXTRACONTAINERCLASS' => $this->table ? 'singletable' : '',
537 'BUTTONLIST_ADDITIONAL' => '',
538 'SEARCHBOX' => '',
539 );
540 // searchbox toolbar
541 if (!$this->modTSconfig['properties']['disableSearchBox'] && ($dblist->HTMLcode || !empty($dblist->searchString))) {
542 $markers['SEARCHBOX'] = $dblist->getSearchBox();
543 $markers['BUTTONLIST_ADDITIONAL'] = '<a href="#" onclick="toggleSearchToolbox(); return false;" title="'
544 . $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.title.searchIcon', TRUE) . '">'
545 . IconUtility::getSpriteIcon('apps-toolbar-menu-search').'</a>';
546 }
547 // Build the <body> for the module
548 $this->content = $this->doc->moduleBody($this->pageinfo, $docHeaderButtons, $markers);
549 // Renders the module page
550 $this->content = $this->doc->render('DB list', $this->content);
551 }
552
553 /**
554 * Outputting the accumulated content to screen
555 *
556 * @return void
557 */
558 public function printContent() {
559 echo $this->content;
560 }
561
562 /**
563 * @return BackendUserAuthentication
564 */
565 protected function getBackendUserAuthentication() {
566 return $GLOBALS['BE_USER'];
567 }
568
569 /**
570 * @return LanguageService
571 */
572 protected function getLanguageService() {
573 return $GLOBALS['LANG'];
574 }
575
576 /**
577 * @return PageRenderer
578 */
579 protected function getPageRenderer() {
580 if ($this->pageRenderer === NULL) {
581 $this->pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
582 }
583
584 return $this->pageRenderer;
585 }
586
587 }