[TASK] BACK_PATH RecordList and friends
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Template / DocumentTemplate.php
1 <?php
2 namespace TYPO3\CMS\Backend\Template;
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\Utility\BackendUtility;
18 use TYPO3\CMS\Backend\Utility\IconUtility;
19 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
20 use TYPO3\CMS\Core\Html\HtmlParser;
21 use TYPO3\CMS\Core\Page\PageRenderer;
22 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
23 use TYPO3\CMS\Core\Utility\GeneralUtility;
24 use TYPO3\CMS\Fluid\View\StandaloneView;
25
26 /**
27 * TYPO3 Backend Template Class
28 *
29 * This class contains functions for starting and ending the HTML of backend modules
30 * It also contains methods for outputting sections of content.
31 * Further there are functions for making icons, links, setting form-field widths etc.
32 * Color scheme and stylesheet definitions are also available here.
33 * Finally this file includes the language class for TYPO3's backend.
34 *
35 * After this file $LANG and $TBE_TEMPLATE are global variables / instances of their respective classes.
36 *
37 * Please refer to Inside TYPO3 for a discussion of how to use this API.
38 */
39 class DocumentTemplate {
40
41 // Vars you typically might want to/should set from outside after making instance of this class:
42 /**
43 * This can be set to the HTML-code for a formtag.
44 * Useful when you need a form to span the whole page; Inserted exactly after the body-tag.
45 *
46 * @var string
47 */
48 public $form = '';
49
50 /**
51 * Similar to $JScode (see below) but used as an associative array to prevent double inclusion of JS code.
52 * This is used to include certain external Javascript libraries before the inline JS code.
53 * <script>-Tags are not wrapped around automatically
54 *
55 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use pageRenderer directly
56 */
57 public $JScodeLibArray = array();
58
59 /**
60 * Additional header code (eg. a JavaScript section) could be accommulated in this var. It will be directly outputted in the header.
61 *
62 * @var string
63 */
64 public $JScode = '';
65
66 /**
67 * Additional header code for ExtJS. It will be included in document header and inserted in a Ext.onReady(function()
68 *
69 * @var string
70 */
71 public $extJScode = '';
72
73 /**
74 * Similar to $JScode but for use as array with associative keys to prevent double inclusion of JS code. a <script> tag is automatically wrapped around.
75 *
76 * @var array
77 */
78 public $JScodeArray = array('jumpToUrl' => '
79 function jumpToUrl(URL) {
80 window.location.href = URL;
81 return false;
82 }
83 ');
84
85 /**
86 * Additional 'page-end' code could be accumulated in this var. It will be outputted at the end of page before </body> and some other internal page-end code.
87 *
88 * @var string
89 */
90 public $postCode = '';
91
92 /**
93 * Doc-type used in the header. Default is xhtml_trans. You can also set it to 'html_3', 'xhtml_strict' or 'xhtml_frames'.
94 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, as it is HTML5
95 */
96 public $docType = '';
97
98 /**
99 * HTML template with markers for module
100 *
101 * @var string
102 */
103 public $moduleTemplate = '';
104
105 /**
106 * The base file (not overlaid by TBE_STYLES) for the current module, useful for hooks when finding out which modules is rendered currently
107 *
108 * @var string
109 */
110 protected $moduleTemplateFilename = '';
111
112 /**
113 * Script ID
114 *
115 * @var string
116 */
117 public $scriptID = '';
118
119 /**
120 * Id which can be set for the body tag. Default value is based on script ID
121 *
122 * @var string
123 */
124 public $bodyTagId = '';
125
126 /**
127 * You can add additional attributes to the body-tag through this variable.
128 *
129 * @var string
130 */
131 public $bodyTagAdditions = '';
132
133 /**
134 * Additional CSS styles which will be added to the <style> section in the header
135 *
136 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use the pageRenderer property for adding CSS styles
137 */
138 public $inDocStyles = '';
139
140 /**
141 * Additional CSS styles which will be added to the <style> section in the header
142 * used as array with associative keys to prevent double inclusion of CSS code
143 *
144 * @var array
145 */
146 public $inDocStylesArray = array();
147
148 /**
149 * Compensation for large documents (used in \TYPO3\CMS\Backend\Form\FormEngine)
150 *
151 * @var float
152 */
153 public $form_largeComp = 1.33;
154
155 /**
156 * If set, then a JavaScript section will be outputted in the bottom of page which will try and update the top.busy session expiry object.
157 *
158 * @var int
159 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
160 */
161 public $endJS = 1;
162
163 // TYPO3 Colorscheme.
164 // If you want to change this, please do so through a skin using the global var $GLOBALS['TBE_STYLES']
165
166 /**
167 * Light background color
168 *
169 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
170 */
171 public $bgColor = '#F7F3EF';
172
173 /**
174 * Steel-blue
175 *
176 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
177 */
178 public $bgColor2 = '#9BA1A8';
179
180 /**
181 * dok.color
182 *
183 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
184 */
185 public $bgColor3 = '#F6F2E6';
186
187 /**
188 * light tablerow background, brownish
189 *
190 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
191 */
192 public $bgColor4 = '#D9D5C9';
193
194 /**
195 * light tablerow background, greenish
196 *
197 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
198 */
199 public $bgColor5 = '#ABBBB4';
200
201 /**
202 * light tablerow background, yellowish, for section headers. Light.
203 *
204 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
205 */
206 public $bgColor6 = '#E7DBA8';
207
208 /**
209 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
210 */
211 public $hoverColor = '#254D7B';
212
213 /**
214 * Filename of stylesheet (relative to PATH_typo3)
215 *
216 * @var string
217 */
218 public $styleSheetFile = '';
219
220 /**
221 * Filename of stylesheet #2 - linked to right after the $this->styleSheetFile script (relative to PATH_typo3)
222 *
223 * @var string
224 */
225 public $styleSheetFile2 = '';
226
227 /**
228 * Filename of a post-stylesheet - included right after all inline styles.
229 *
230 * @var string
231 */
232 public $styleSheetFile_post = '';
233
234 /**
235 * Background image of page (relative to PATH_typo3)
236 *
237 * @var string
238 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use a stylesheet instead
239 */
240 public $backGroundImage = '';
241
242 /**
243 * Inline css styling set from TBE_STYLES array
244 *
245 * @var string
246 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use inDocStylesArray['TBEstyle']
247 */
248 public $inDocStyles_TBEstyle = '';
249
250 /**
251 * Whether to use the X-UA-Compatible meta tag
252 *
253 * @var bool
254 */
255 protected $useCompatibilityTag = TRUE;
256
257 /**
258 * X-Ua-Compatible version output in meta tag
259 *
260 * @var string
261 */
262 protected $xUaCompatibilityVersion = 'IE=edge';
263
264 // Skinning
265 /**
266 * stylesheets from core
267 *
268 * @var array
269 */
270 protected $stylesheetsCore = array(
271 'generatedSprites' => '../typo3temp/sprites/'
272 );
273
274 /**
275 * Include these CSS directories from skins by default
276 *
277 * @var array
278 */
279 protected $stylesheetsSkins = array(
280 'structure' => 'Resources/Public/Css/structure/',
281 'visual' => 'Resources/Public/Css/visual/'
282 );
283
284 /**
285 * JavaScript files loaded for every page in the Backend
286 *
287 * @var array
288 */
289 protected $jsFiles = array();
290
291 /**
292 * JavaScript files loaded for every page in the Backend, but explicitly excluded from concatenation (useful for libraries etc.)
293 *
294 * @var array
295 */
296 protected $jsFilesNoConcatenation = array();
297
298 /**
299 * Will output the parsetime of the scripts in milliseconds (for admin-users).
300 * Set this to FALSE when releasing TYPO3. Only for dev.
301 *
302 * @var bool
303 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
304 */
305 public $parseTimeFlag = FALSE;
306
307 /**
308 * internal character set, nowadays utf-8 for everything
309 *
310 * @var string
311 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, as it is always utf-8
312 */
313 protected $charset = 'utf-8';
314
315 /**
316 * Indicates if a <div>-output section is open
317 *
318 * @var int
319 * @internal
320 */
321 public $sectionFlag = 0;
322
323 /**
324 * (Default) Class for wrapping <DIV>-tag of page. Is set in class extensions.
325 *
326 * @var string
327 */
328 public $divClass = '';
329
330 /**
331 * @var string
332 */
333 public $pageHeaderBlock = '';
334
335 /**
336 * @var string
337 */
338 public $endOfPageJsBlock = '';
339
340 /**
341 * @var bool
342 */
343 public $hasDocheader = TRUE;
344
345 /**
346 * @var PageRenderer
347 */
348 protected $pageRenderer = NULL;
349
350 /**
351 * Alternative template file
352 *
353 * @var string
354 */
355 protected $pageHeaderFooterTemplateFile = '';
356
357 /**
358 * @var bool
359 */
360 protected $extDirectStateProvider = FALSE;
361
362 /**
363 * Whether flashmessages should be rendered or not
364 *
365 * @var bool $showFlashMessages
366 */
367 public $showFlashMessages = TRUE;
368
369 const STATUS_ICON_ERROR = 3;
370 const STATUS_ICON_WARNING = 2;
371 const STATUS_ICON_NOTIFICATION = 1;
372 const STATUS_ICON_OK = -1;
373
374 /**
375 * Constructor
376 */
377 public function __construct() {
378 // Initializes the page rendering object:
379 $this->initPageRenderer();
380
381 // load Legacy CSS Support
382 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LegacyCssClasses');
383
384 // Setting default scriptID:
385 if (($temp_M = (string)GeneralUtility::_GET('M')) && $GLOBALS['TBE_MODULES']['_PATHS'][$temp_M]) {
386 $this->scriptID = preg_replace('/^.*\\/(sysext|ext)\\//', 'ext/', $GLOBALS['TBE_MODULES']['_PATHS'][$temp_M] . 'index.php');
387 } else {
388 $this->scriptID = preg_replace('/^.*\\/(sysext|ext)\\//', 'ext/', \TYPO3\CMS\Core\Utility\PathUtility::stripPathSitePrefix(PATH_thisScript));
389 }
390 if (TYPO3_mainDir != 'typo3/' && substr($this->scriptID, 0, strlen(TYPO3_mainDir)) == TYPO3_mainDir) {
391 // This fixes if TYPO3_mainDir has been changed so the script ids are STILL "typo3/..."
392 $this->scriptID = 'typo3/' . substr($this->scriptID, strlen(TYPO3_mainDir));
393 }
394 $this->bodyTagId = preg_replace('/[^A-Za-z0-9-]/', '-', $this->scriptID);
395 // Individual configuration per script? If so, make a recursive merge of the arrays:
396 if (is_array($GLOBALS['TBE_STYLES']['scriptIDindex'][$this->scriptID])) {
397 // Make copy
398 $ovr = $GLOBALS['TBE_STYLES']['scriptIDindex'][$this->scriptID];
399 // merge styles.
400 \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($GLOBALS['TBE_STYLES'], $ovr);
401 // Have to unset - otherwise the second instantiation will do it again!
402 unset($GLOBALS['TBE_STYLES']['scriptIDindex'][$this->scriptID]);
403 }
404 // Main Stylesheets:
405 if ($GLOBALS['TBE_STYLES']['stylesheet']) {
406 $this->styleSheetFile = $GLOBALS['TBE_STYLES']['stylesheet'];
407 }
408 if ($GLOBALS['TBE_STYLES']['stylesheet2']) {
409 $this->styleSheetFile2 = $GLOBALS['TBE_STYLES']['stylesheet2'];
410 }
411 if ($GLOBALS['TBE_STYLES']['styleSheetFile_post']) {
412 $this->styleSheetFile_post = $GLOBALS['TBE_STYLES']['styleSheetFile_post'];
413 }
414 if ($GLOBALS['TBE_STYLES']['inDocStyles_TBEstyle']) {
415 $this->inDocStylesArray['TBEstyle'] = $GLOBALS['TBE_STYLES']['inDocStyles_TBEstyle'];
416 }
417 // include all stylesheets
418 foreach ($this->getSkinStylesheetDirectories() as $stylesheetDirectory) {
419 $this->addStylesheetDirectory($stylesheetDirectory);
420 }
421 // Background image
422 if ($GLOBALS['TBE_STYLES']['background']) {
423 GeneralUtility::deprecationLog('Usage of $TBE_STYLES["background"] is deprecated. Please use stylesheets directly.');
424 }
425 }
426
427 /**
428 * Initializes the page renderer object
429 */
430 protected function initPageRenderer() {
431 if ($this->pageRenderer !== NULL) {
432 return;
433 }
434 $this->pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
435 $this->pageRenderer->setLanguage($GLOBALS['LANG']->lang);
436 $this->pageRenderer->enableConcatenateFiles();
437 $this->pageRenderer->enableCompressCss();
438 $this->pageRenderer->enableCompressJavascript();
439 // Add all JavaScript files defined in $this->jsFiles to the PageRenderer
440 foreach ($this->jsFilesNoConcatenation as $file) {
441 $this->pageRenderer->addJsFile(
442 $GLOBALS['BACK_PATH'] . $file,
443 'text/javascript',
444 TRUE,
445 FALSE,
446 '',
447 TRUE
448 );
449 }
450 // Add all JavaScript files defined in $this->jsFiles to the PageRenderer
451 foreach ($this->jsFiles as $file) {
452 $this->pageRenderer->addJsFile($GLOBALS['BACK_PATH'] . $file);
453 }
454 if ((int)$GLOBALS['TYPO3_CONF_VARS']['BE']['debug'] === 1) {
455 $this->pageRenderer->enableDebugMode();
456 }
457 }
458
459 /**
460 * Gets instance of PageRenderer configured with the current language, file references and debug settings
461 *
462 * @return PageRenderer
463 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8.
464 */
465 public function getPageRenderer() {
466 GeneralUtility::logDeprecatedFunction();
467 $this->initPageRenderer();
468
469 return $this->pageRenderer;
470 }
471
472 /**
473 * Sets inclusion of StateProvider
474 *
475 * @return void
476 */
477 public function setExtDirectStateProvider() {
478 $this->extDirectStateProvider = TRUE;
479 }
480
481 /*****************************************
482 *
483 * EVALUATION FUNCTIONS
484 * Various centralized processing
485 *
486 *****************************************/
487 /**
488 * Makes click menu link (context sensitive menu)
489 * Returns $str (possibly an <|img> tag/icon) wrapped in a link which will activate the context sensitive menu for the record ($table/$uid) or file ($table = file)
490 * The link will load the top frame with the parameter "&item" which is the table,uid and listFr arguments imploded by "|": rawurlencode($table.'|'.$uid.'|'.$listFr)
491 *
492 * @param string $str String to be wrapped in link, typ. image tag.
493 * @param string $table Table name/File path. If the icon is for a database record, enter the tablename from $GLOBALS['TCA']. If a file then enter the absolute filepath
494 * @param int $uid If icon is for database record this is the UID for the record from $table
495 * @param bool $listFr Tells the top frame script that the link is coming from a "list" frame which means a frame from within the backend content frame.
496 * @param string $addParams Additional GET parameters for the link to the ClickMenu AJAX request
497 * @param string $enDisItems Enable / Disable click menu items. Example: "+new,view" will display ONLY these two items (and any spacers in between), "new,view" will display all BUT these two items.
498 * @param bool $returnTagParameters If set, will return only the onclick JavaScript, not the whole link.
499 * @return string The link-wrapped input string.
500 */
501 public function wrapClickMenuOnIcon($content, $table, $uid = 0, $listFr = TRUE, $addParams = '', $enDisItems = '', $returnTagParameters = FALSE) {
502 $tagParameters = array(
503 'class' => 't3-js-clickmenutrigger',
504 'data-table' => $table,
505 'data-uid' => (int)$uid !== 0 ? (int)$uid : '',
506 'data-listframe' => $listFr,
507 'data-iteminfo' => str_replace('+', '%2B', $enDisItems),
508 'data-parameters' => $addParams,
509 );
510
511 if ($returnTagParameters) {
512 return $tagParameters;
513 } else {
514 return '<a href="#" ' . GeneralUtility::implodeAttributes($tagParameters, TRUE) . '>' . $content . '</a>';
515 }
516 }
517
518 /**
519 * Makes link to page $id in frontend (view page)
520 * Returns an icon which links to the frontend index.php document for viewing the page with id $id
521 * $id must be a page-uid
522 * If the BE_USER has access to Web>List then a link to that module is shown as well (with return-url)
523 *
524 * @param int $id The page id
525 * @param string $_ @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
526 * @return string HTML string with linked icon(s)
527 */
528 public function viewPageIcon($id, $_ = '') {
529 // If access to Web>List for user, then link to that module.
530 $str = BackendUtility::getListViewLink(array(
531 'id' => $id,
532 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
533 ), $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.showList'));
534 // Make link to view page
535 $str .= '<a href="#" onclick="' . htmlspecialchars(BackendUtility::viewOnClick($id, '', BackendUtility::BEgetRootLine($id))) . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.showPage', TRUE) . '">' . IconUtility::getSpriteIcon('actions-document-view') . '</a>';
536 return $str;
537 }
538
539 /**
540 * Returns a URL with a command to TYPO3 Core Engine (tce_db.php)
541 * See description of the API elsewhere.
542 *
543 * @param string $params is a set of GET params to send to tce_db.php. Example: "&cmd[tt_content][123][move]=456" or "&data[tt_content][123][hidden]=1&data[tt_content][123][title]=Hello%20World
544 * @param string|int $redirectUrl Redirect URL, default is to use GeneralUtility::getIndpEnv('REQUEST_URI'), -1 means to generate an URL for JavaScript using T3_THIS_LOCATION
545 * @return string URL to BackendUtility::getModuleUrl('tce_db') + parameters
546 * @see \TYPO3\CMS\Backend\Utility\BackendUtility::editOnClick()
547 */
548 public function issueCommand($params, $redirectUrl = '') {
549 /** @var BackendUserAuthentication $beUser */
550 $beUser = $GLOBALS['BE_USER'];
551 $urlParameters = [
552 'prErr' => 1,
553 'uPT' => 1,
554 'vC' => $beUser->veriCode()
555 ];
556 $url = BackendUtility::getModuleUrl('tce_db', $urlParameters) . $params . BackendUtility::getUrlToken('tceAction') . '&redirect=';
557 if ((int)$redirectUrl === -1) {
558 $url = GeneralUtility::quoteJSvalue($url) . '+T3_THIS_LOCATION';
559 } else {
560 $url .= rawurlencode($redirectUrl ?: GeneralUtility::getIndpEnv('REQUEST_URI'));
561 }
562 return $url;
563 }
564
565 /**
566 * Makes the header (icon+title) for a page (or other record). Used in most modules under Web>*
567 * $table and $row must be a tablename/record from that table
568 * $path will be shown as alt-text for the icon.
569 * The title will be truncated to 45 chars.
570 *
571 * @param string $table Table name
572 * @param array $row Record row
573 * @param string $path Alt text
574 * @param bool $noViewPageIcon Set $noViewPageIcon TRUE if you don't want a magnifier-icon for viewing the page in the frontend
575 * @param array $tWrap is an array with indexes 0 and 1 each representing HTML-tags (start/end) which will wrap the title
576 * @param bool $enableClickMenu If TRUE, render click menu code around icon image
577 * @return string HTML content
578 */
579 public function getHeader($table, $row, $path, $noViewPageIcon = FALSE, $tWrap = array('', ''), $enableClickMenu = TRUE) {
580 $viewPage = '';
581 if (is_array($row) && $row['uid']) {
582 $iconImgTag = IconUtility::getSpriteIconForRecord($table, $row, array('title' => htmlspecialchars($path)));
583 $title = strip_tags(BackendUtility::getRecordTitle($table, $row));
584 $viewPage = $noViewPageIcon ? '' : $this->viewPageIcon($row['uid']);
585 } else {
586 $iconImgTag = IconUtility::getSpriteIcon('apps-pagetree-page-domain', array('title' => htmlspecialchars($path)));
587 $title = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'];
588 }
589
590 if ($enableClickMenu) {
591 $iconImgTag = $this->wrapClickMenuOnIcon($iconImgTag, $table, $row['uid']);
592 }
593
594 return '<span class="typo3-moduleHeader">' . $iconImgTag . $viewPage . $tWrap[0] . htmlspecialchars(GeneralUtility::fixed_lgd_cs($title, 45)) . $tWrap[1] . '</span>';
595 }
596
597 /**
598 * Like ->getHeader() but for files and folders
599 * Returns the icon with the path of the file/folder set in the alt/title attribute. Shows the name after the icon.
600 *
601 * @param \TYPO3\CMS\Core\Resource\ResourceInterface $resource
602 * @param array $tWrap is an array with indexes 0 and 1 each representing HTML-tags (start/end) which will wrap the title
603 * @param bool $enableClickMenu If TRUE, render click menu code around icon image
604 * @return string
605 */
606 public function getResourceHeader(\TYPO3\CMS\Core\Resource\ResourceInterface $resource, $tWrap = array('', ''), $enableClickMenu = TRUE) {
607 $path = $resource->getStorage()->getName() . $resource->getParentFolder()->getIdentifier();
608 $iconImgTag = IconUtility::getSpriteIconForResource($resource, array('title' => htmlspecialchars($path)));
609
610 if ($enableClickMenu && ($resource instanceof \TYPO3\CMS\Core\Resource\File)) {
611 $metaData = $resource->_getMetaData();
612 $iconImgTag = $this->wrapClickMenuOnIcon($iconImgTag, 'sys_file_metadata', $metaData['uid']);
613 }
614
615 return '<span class="typo3-moduleHeader">' . $iconImgTag . $tWrap[0] . htmlspecialchars(GeneralUtility::fixed_lgd_cs($resource->getName(), 45)) . $tWrap[1] . '</span>';
616 }
617
618 /**
619 * Returns a linked shortcut-icon which will call the shortcut frame and set a shortcut there back to the calling page/module
620 *
621 * @param string $gvList Is the list of GET variables to store (if any)
622 * @param string $setList Is the list of SET[] variables to store (if any) - SET[] variables a stored in $GLOBALS["SOBE"]->MOD_SETTINGS for backend modules
623 * @param string $modName Module name string
624 * @param string|int $motherModName Is used to enter the "parent module name" if the module is a submodule under eg. Web>* or File>*. You can also set this value to 1 in which case the currentLoadedModule is sent to the shortcut script (so - not a fixed value!) - that is used in file_edit and wizard_rte modules where those are really running as a part of another module.
625 * @return string HTML content
626 */
627 public function makeShortcutIcon($gvList, $setList, $modName, $motherModName = '') {
628 $storeUrl = $this->makeShortcutUrl($gvList, $setList);
629 $pathInfo = parse_url(GeneralUtility::getIndpEnv('REQUEST_URI'));
630 // Fallback for alt_mod. We still pass in the old xMOD... stuff, but TBE_MODULES only knows about "record_edit".
631 // We still need to pass the xMOD name to createShortcut below, since this is used for icons.
632 $moduleName = $modName === 'xMOD_alt_doc.php' ? 'record_edit' : $modName;
633 // Add the module identifier automatically if typo3/index.php is used:
634 if (GeneralUtility::_GET('M') !== NULL && isset($GLOBALS['TBE_MODULES']['_PATHS'][$moduleName])) {
635 $storeUrl = '&M=' . $moduleName . $storeUrl;
636 }
637 if ((int)$motherModName === 1) {
638 $motherModule = 'top.currentModuleLoaded';
639 } elseif ($motherModName) {
640 $motherModule = GeneralUtility::quoteJSvalue($motherModName);
641 } else {
642 $motherModule = '\'\'';
643 }
644 $confirmationText = GeneralUtility::quoteJSvalue($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.makeBookmark'));
645 $url = GeneralUtility::quoteJSvalue(rawurlencode($pathInfo['path'] . '?' . $storeUrl));
646 $onClick = 'top.TYPO3.ShortcutMenu.createShortcut(' . GeneralUtility::quoteJSvalue(rawurlencode($modName)) . ', ' . $url . ', ' . $confirmationText . ', ' . $motherModule . ');return false;';
647 return '<a href="#" onclick="' . htmlspecialchars($onClick) . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.makeBookmark', TRUE) . '">' . IconUtility::getSpriteIcon('actions-system-shortcut-new') . '</a>';
648 }
649
650 /**
651 * MAKE url for storing
652 * Internal func
653 *
654 * @param string $gvList Is the list of GET variables to store (if any)
655 * @param string $setList Is the list of SET[] variables to store (if any) - SET[] variables a stored in $GLOBALS["SOBE"]->MOD_SETTINGS for backend modules
656 * @return string
657 * @access private
658 * @see makeShortcutIcon()
659 */
660 public function makeShortcutUrl($gvList, $setList) {
661 $GET = GeneralUtility::_GET();
662 $storeArray = array_merge(GeneralUtility::compileSelectedGetVarsFromArray($gvList, $GET), array('SET' => GeneralUtility::compileSelectedGetVarsFromArray($setList, (array)$GLOBALS['SOBE']->MOD_SETTINGS)));
663 $storeUrl = GeneralUtility::implodeArrayForUrl('', $storeArray);
664 return $storeUrl;
665 }
666
667 /**
668 * Returns <input> attributes to set the width of an text-type input field.
669 * For client browsers with no CSS support the cols/size attribute is returned.
670 * For CSS compliant browsers (recommended) a ' style="width: ...px;"' is returned.
671 *
672 * @param int $size A relative number which multiplied with approx. 10 will lead to the width in pixels
673 * @param bool $textarea A flag you can set for textareas - DEPRECATED as there is no difference any more between the two
674 * @param string $styleOverride A string which will be returned as attribute-value for style="" instead of the calculated width (if CSS is enabled)
675 * @return string Tag attributes for an <input> tag (regarding width)
676 */
677 public function formWidth($size = 48, $textarea = FALSE, $styleOverride = '') {
678 return ' style="' . ($styleOverride ?: 'width:' . ceil($size * 9.58) . 'px;') . '"';
679 }
680
681 /**
682 * Returns JavaScript variables setting the returnUrl and thisScript location for use by JavaScript on the page.
683 * Used in fx. db_list.php (Web>List)
684 *
685 * @param string $thisLocation URL to "this location" / current script
686 * @return string Urls are returned as JavaScript variables T3_RETURN_URL and T3_THIS_LOCATION
687 * @see typo3/db_list.php
688 */
689 public function redirectUrls($thisLocation = '') {
690 $thisLocation = $thisLocation ? $thisLocation : GeneralUtility::linkThisScript(array(
691 'CB' => '',
692 'SET' => '',
693 'cmd' => '',
694 'popViewId' => ''
695 ));
696 $out = '
697 var T3_RETURN_URL = ' . GeneralUtility::quoteJSvalue(str_replace('%20', '', rawurlencode(GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('returnUrl'))))) . ';
698 var T3_THIS_LOCATION = ' . GeneralUtility::quoteJSvalue(str_replace('%20', '', rawurlencode($thisLocation))) . '
699 ';
700 return $out;
701 }
702
703 /**
704 * Returns a formatted string of $tstamp
705 * Uses $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'] and $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'] to format date and time
706 *
707 * @param int $tstamp UNIX timestamp, seconds since 1970
708 * @param int $type How much data to show: $type = 1: hhmm, $type = 10: ddmmmyy
709 * @return string Formatted timestamp
710 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use the corresponding methods in BackendUtility
711 */
712 public function formatTime($tstamp, $type) {
713 GeneralUtility::logDeprecatedFunction();
714 $dateStr = '';
715 switch ($type) {
716 case 1:
717 $dateStr = date($GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'], $tstamp);
718 break;
719 case 10:
720 $dateStr = date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], $tstamp);
721 break;
722 }
723 return $dateStr;
724 }
725
726 /**
727 * Returns script parsetime IF ->parseTimeFlag is set and user is "admin"
728 * Automatically outputted in page end
729 *
730 * @return string HTML formated with <p>-tags
731 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
732 */
733 public function parseTime() {
734 GeneralUtility::logDeprecatedFunction();
735 if ($this->parseTimeFlag && $GLOBALS['BE_USER']->isAdmin()) {
736 return '<p>(ParseTime: ' . (GeneralUtility::milliseconds() - $GLOBALS['PARSETIME_START']) . ' ms</p>
737 <p>REQUEST_URI-length: ' . strlen(GeneralUtility::getIndpEnv('REQUEST_URI')) . ')</p>';
738 }
739 }
740
741 /**
742 * Defines whether to use the X-UA-Compatible meta tag.
743 *
744 * @param bool $useCompatibilityTag Whether to use the tag
745 * @return void
746 */
747 public function useCompatibilityTag($useCompatibilityTag = TRUE) {
748 $this->useCompatibilityTag = (bool)$useCompatibilityTag;
749 }
750
751 /*****************************************
752 *
753 * PAGE BUILDING FUNCTIONS.
754 * Use this to build the HTML of your backend modules
755 *
756 *****************************************/
757 /**
758 * Returns page start
759 * This includes the proper header with charset, title, meta tag and beginning body-tag.
760 *
761 * @param string $title HTML Page title for the header
762 * @param bool $includeCsh flag for including CSH
763 * @return string Returns the whole header section of a HTML-document based on settings in internal variables (like styles, javascript code, charset, generator and docType)
764 * @see endPage()
765 */
766 public function startPage($title, $includeCsh = TRUE) {
767 // hook pre start page
768 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preStartPageHook'])) {
769 $preStartPageHook = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preStartPageHook'];
770 if (is_array($preStartPageHook)) {
771 $hookParameters = array(
772 'title' => &$title
773 );
774 foreach ($preStartPageHook as $hookFunction) {
775 GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
776 }
777 }
778 }
779 // alternative template for Header and Footer
780 if ($this->pageHeaderFooterTemplateFile) {
781 $file = GeneralUtility::getFileAbsFileName($this->pageHeaderFooterTemplateFile, TRUE);
782 if ($file) {
783 $this->pageRenderer->setTemplateFile($file);
784 }
785 }
786
787
788
789 // Disable rendering of XHTML tags
790 $this->pageRenderer->setRenderXhtml(FALSE);
791
792 $languageCode = $this->pageRenderer->getLanguage() === 'default' ? 'en' : $this->pageRenderer->getLanguage();
793 $this->pageRenderer->setHtmlTag('<html lang="' . $languageCode . '">');
794
795 // Include the JS for the Context Sensitive Help
796 // @todo: right now this is a hard dependency on csh manual, as the whole help system should be moved to
797 // the extension. The core provides an API for adding help, and rendering help, but the rendering
798 // should be up to the extension itself
799 if ($includeCsh && ExtensionManagementUtility::isLoaded('cshmanual')) {
800 $this->loadCshJavascript();
801 }
802
803 $headerStart = '<!DOCTYPE html>';
804 $this->pageRenderer->setXmlPrologAndDocType($headerStart);
805 $this->pageRenderer->setHeadTag('<head>' . LF . '<!-- TYPO3 Script ID: ' . htmlspecialchars($this->scriptID) . ' -->');
806 header('Content-Type:text/html;charset=utf-8');
807 $this->pageRenderer->setCharSet('utf-8');
808 $this->pageRenderer->addMetaTag($this->generator());
809 $this->pageRenderer->addMetaTag('<meta name="robots" content="noindex,follow">');
810 $this->pageRenderer->addMetaTag('<meta charset="utf-8">');
811 $this->pageRenderer->addMetaTag('<meta name="viewport" content="width=device-width, initial-scale=1">');
812 $this->pageRenderer->setFavIcon($this->getBackendFavicon());
813 if ($this->useCompatibilityTag) {
814 $this->pageRenderer->addMetaTag($this->xUaCompatible($this->xUaCompatibilityVersion));
815 }
816 $this->pageRenderer->setTitle($title);
817 // add docstyles
818 $this->docStyle();
819 if ($this->extDirectStateProvider) {
820 $this->pageRenderer->addJsFile('sysext/backend/Resources/Public/JavaScript/ExtDirect.StateProvider.js');
821 }
822 // Add jsCode for overriding the console with a debug panel connection
823 $this->pageRenderer->addJsInlineCode('consoleOverrideWithDebugPanel', 'if (typeof top.Ext === "object") {
824 top.Ext.onReady(function() {
825 if (typeof console === "undefined") {
826 if (top && top.TYPO3 && top.TYPO3.Backend && top.TYPO3.Backend.DebugConsole) {
827 console = top.TYPO3.Backend.DebugConsole;
828 } else {
829 console = {
830 log: Ext.log,
831 info: Ext.log,
832 warn: Ext.log,
833 error: Ext.log
834 };
835 }
836 }
837 });
838 }
839 ', FALSE);
840 $this->pageRenderer->addHeaderData($this->JScode);
841 foreach ($this->JScodeArray as $name => $code) {
842 $this->pageRenderer->addJsInlineCode($name, $code, FALSE);
843 }
844 if (!empty($this->JScodeLibArray)) {
845 GeneralUtility::deprecationLog('DocumentTemplate->JScodeLibArray is deprecated since TYPO3 CMS 7. Use the functionality within pageRenderer directly');
846 foreach ($this->JScodeLibArray as $library) {
847 $this->pageRenderer->addHeaderData($library);
848 }
849 }
850 if ($this->extJScode) {
851 $this->pageRenderer->addExtOnReadyCode($this->extJScode);
852 }
853
854 // Load jquery and twbs JS libraries on every backend request
855 $this->pageRenderer->loadJquery();
856 // Note: please do not reference "bootstrap" outside of the TYPO3 Core (not in your own extensions)
857 // as this is preliminary as long as Twitter bootstrap does not support AMD modules
858 // this logic will be changed once Twitter bootstrap 4 is included
859 $this->pageRenderer->addJsFile('sysext/core/Resources/Public/JavaScript/Contrib/bootstrap/bootstrap.js');
860
861 // hook for additional headerData
862 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preHeaderRenderHook'])) {
863 $preHeaderRenderHook = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preHeaderRenderHook'];
864 if (is_array($preHeaderRenderHook)) {
865 $hookParameters = array(
866 'pageRenderer' => &$this->pageRenderer
867 );
868 foreach ($preHeaderRenderHook as $hookFunction) {
869 GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
870 }
871 }
872 }
873 // Construct page header.
874 $str = $this->pageRenderer->render(PageRenderer::PART_HEADER);
875 $this->JScode = ($this->extJScode = '');
876 $this->JScodeArray = array();
877 $this->endOfPageJsBlock = $this->pageRenderer->render(PageRenderer::PART_FOOTER);
878 $str .= $this->docBodyTagBegin() . ($this->divClass ? '
879
880 <!-- Wrapping DIV-section for whole page BEGIN -->
881 <div class="' . $this->divClass . '">
882 ' : '') . trim($this->form);
883 return $str;
884 }
885
886 /**
887 * Returns page end; This includes finishing form, div, body and html tags.
888 *
889 * @return string The HTML end of a page
890 * @see startPage()
891 */
892 public function endPage() {
893 $str = $this->sectionEnd() . $this->postCode . $this->wrapScriptTags(BackendUtility::getUpdateSignalCode()) . ($this->form ? '
894 </form>' : '');
895 // If something is in buffer like debug, put it to end of page
896 if (ob_get_contents()) {
897 $str .= ob_get_clean();
898 if (!headers_sent()) {
899 header('Content-Encoding: None');
900 }
901 }
902 $str .= ($this->divClass ? '
903
904 <!-- Wrapping DIV-section for whole page END -->
905 </div>' : '') . $this->endOfPageJsBlock;
906
907 // Logging: Can't find better place to put it:
908 if (TYPO3_DLOG) {
909 GeneralUtility::devLog('END of BACKEND session', \TYPO3\CMS\Backend\Template\DocumentTemplate::class, 0, array('_FLUSH' => TRUE));
910 }
911 return $str;
912 }
913
914 /**
915 * Shortcut for render the complete page of a module
916 *
917 * @param string $title page title
918 * @param string $content page content
919 * @param bool $includeCsh flag for including csh code
920 * @return string complete page
921 */
922 public function render($title, $content, $includeCsh = TRUE) {
923 $pageContent = $this->startPage($title, $includeCsh);
924 $pageContent .= $content;
925 $pageContent .= $this->endPage();
926 return $this->insertStylesAndJS($pageContent);
927 }
928
929 /**
930 * Returns the header-bar in the top of most backend modules
931 * Closes section if open.
932 *
933 * @param string $text The text string for the header
934 * @return string HTML content
935 */
936 public function header($text) {
937 $str = '
938
939 <!-- MAIN Header in page top -->
940 <h1>' . htmlspecialchars($text) . '</h1>
941 ';
942 return $this->sectionEnd() . $str;
943 }
944
945 /**
946 * Begins an output section and sets header and content
947 *
948 * @param string $label The header
949 * @param string $text The HTML-content
950 * @param bool $nostrtoupper A flag that will prevent the header from being converted to uppercase
951 * @param bool $sH Defines the type of header (if set, "<h3>" rather than the default "h4")
952 * @param int $type The number of an icon to show with the header (see the icon-function). -1,1,2,3
953 * @param bool $allowHTMLinHeader If set, HTML tags are allowed in $label (otherwise this value is by default htmlspecialchars()'ed)
954 * @return string HTML content
955 * @see icons(), sectionHeader()
956 */
957 public function section($label, $text, $nostrtoupper = FALSE, $sH = FALSE, $type = 0, $allowHTMLinHeader = FALSE) {
958 $str = '';
959 // Setting header
960 if ($label) {
961 if (!$allowHTMLinHeader) {
962 $label = htmlspecialchars($label);
963 }
964 $str .= $this->sectionHeader($this->icons($type) . $label, $sH, $nostrtoupper ? '' : ' class="uppercase"');
965 }
966 // Setting content
967 $str .= '
968
969 <!-- Section content -->
970 ' . $text;
971 return $this->sectionBegin() . $str;
972 }
973
974 /**
975 * Inserts a divider image
976 * Ends a section (if open) before inserting the image
977 *
978 * @param int $dist The margin-top/-bottom of the <hr> ruler.
979 * @return string HTML content
980 */
981 public function divider($dist) {
982 $dist = (int)$dist;
983 $str = '
984
985 <!-- DIVIDER -->
986 <hr style="margin-top: ' . $dist . 'px; margin-bottom: ' . $dist . 'px;" />
987 ';
988 return $this->sectionEnd() . $str;
989 }
990
991 /**
992 * Returns a blank <div>-section with a height
993 *
994 * @param int $dist Padding-top for the div-section (should be margin-top but konqueror (3.1) doesn't like it :-(
995 * @return string HTML content
996 */
997 public function spacer($dist) {
998 if ($dist > 0) {
999 return '
1000
1001 <!-- Spacer element -->
1002 <div style="padding-top: ' . (int)$dist . 'px;"></div>
1003 ';
1004 }
1005 }
1006
1007 /**
1008 * Make a section header.
1009 * Begins a section if not already open.
1010 *
1011 * @param string $label The label between the <h3> or <h4> tags. (Allows HTML)
1012 * @param bool $sH If set, <h3> is used, otherwise <h4>
1013 * @param string $addAttrib Additional attributes to h-tag, eg. ' class=""'
1014 * @return string HTML content
1015 */
1016 public function sectionHeader($label, $sH = FALSE, $addAttrib = '') {
1017 $tag = $sH ? 'h2' : 'h3';
1018 if ($addAttrib && $addAttrib[0] !== ' ') {
1019 $addAttrib = ' ' . $addAttrib;
1020 }
1021 $str = '
1022
1023 <!-- Section header -->
1024 <' . $tag . $addAttrib . '>' . $label . '</' . $tag . '>
1025 ';
1026 return $this->sectionBegin() . $str;
1027 }
1028
1029 /**
1030 * Begins an output section.
1031 * Returns the <div>-begin tag AND sets the ->sectionFlag TRUE (if the ->sectionFlag is not already set!)
1032 * You can call this function even if a section is already begun since the function will only return something if the sectionFlag is not already set!
1033 *
1034 * @return string HTML content
1035 */
1036 public function sectionBegin() {
1037 if (!$this->sectionFlag) {
1038 $this->sectionFlag = 1;
1039 $str = '
1040
1041 <!-- ***********************
1042 Begin output section.
1043 *********************** -->
1044 <div>
1045 ';
1046 return $str;
1047 } else {
1048 return '';
1049 }
1050 }
1051
1052 /**
1053 * Ends and output section
1054 * Returns the </div>-end tag AND clears the ->sectionFlag (but does so only IF the sectionFlag is set - that is a section is 'open')
1055 * See sectionBegin() also.
1056 *
1057 * @return string HTML content
1058 */
1059 public function sectionEnd() {
1060 if ($this->sectionFlag) {
1061 $this->sectionFlag = 0;
1062 return '
1063 </div>
1064 <!-- *********************
1065 End output section.
1066 ********************* -->
1067 ';
1068 } else {
1069 return '';
1070 }
1071 }
1072
1073 /**
1074 * If a form-tag is defined in ->form then and end-tag for that <form> element is outputted
1075 * Further a JavaScript section is outputted which will update the top.busy session-expiry object (unless $this->endJS is set to FALSE)
1076 *
1077 * @return string HTML content (<script> tag section)
1078 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, nothing there to output anymore
1079 */
1080 public function endPageJS() {
1081 GeneralUtility::logDeprecatedFunction();
1082 return '';
1083 }
1084
1085 /**
1086 * Creates the bodyTag.
1087 * You can add to the bodyTag by $this->bodyTagAdditions
1088 *
1089 * @return string HTML body tag
1090 */
1091 public function docBodyTagBegin() {
1092 return '<body ' . trim(($this->bodyTagAdditions . ($this->bodyTagId ? ' id="' . $this->bodyTagId . '"' : ''))) . '>';
1093 }
1094
1095 /**
1096 * Outputting document style
1097 *
1098 * @return string HTML style section/link tags
1099 */
1100 public function docStyle() {
1101 // Implode it all:
1102 $inDocStyles = implode(LF, $this->inDocStylesArray);
1103
1104 // Reset styles so they won't be added again in insertStylesAndJS()
1105 $this->inDocStylesArray = array();
1106
1107 if ($this->styleSheetFile) {
1108 $this->pageRenderer->addCssFile($this->styleSheetFile);
1109 }
1110 if ($this->styleSheetFile2) {
1111 $this->pageRenderer->addCssFile($this->styleSheetFile2);
1112 }
1113
1114 if ($inDocStyles !== '') {
1115 $this->pageRenderer->addCssInlineBlock('inDocStyles', $inDocStyles . LF . '/*###POSTCSSMARKER###*/');
1116 }
1117
1118 if ($this->styleSheetFile_post) {
1119 $this->pageRenderer->addCssFile($this->styleSheetFile_post);
1120 }
1121 }
1122
1123 /**
1124 * Insert additional style sheet link
1125 *
1126 * @param string $key some key identifying the style sheet
1127 * @param string $href uri to the style sheet file
1128 * @param string $title value for the title attribute of the link element
1129 * @param string $relation value for the rel attribute of the link element
1130 * @return void
1131 */
1132 public function addStyleSheet($key, $href, $title = '', $relation = 'stylesheet') {
1133 $this->pageRenderer->addCssFile($href, $relation, 'screen', $title);
1134 }
1135
1136 /**
1137 * Add all *.css files of the directory $path to the stylesheets
1138 *
1139 * @param string $path directory to add
1140 * @return void
1141 */
1142 public function addStyleSheetDirectory($path) {
1143 // Calculation needed, when TYPO3 source is used via a symlink
1144 // absolute path to the stylesheets
1145 $filePath = dirname(GeneralUtility::getIndpEnv('SCRIPT_FILENAME')) . '/' . $GLOBALS['BACK_PATH'] . $path;
1146 // Clean the path
1147 $resolvedPath = GeneralUtility::resolveBackPath($filePath);
1148 // Read all files in directory and sort them alphabetically
1149 $files = GeneralUtility::getFilesInDir($resolvedPath, 'css', FALSE, 1);
1150 foreach ($files as $file) {
1151 $this->pageRenderer->addCssFile($GLOBALS['BACK_PATH'] . $path . $file, 'stylesheet', 'all');
1152 }
1153 }
1154
1155 /**
1156 * Insert post rendering document style into already rendered content
1157 * This is needed for extobjbase
1158 *
1159 * @param string $content style-content to insert.
1160 * @return string content with inserted styles
1161 */
1162 public function insertStylesAndJS($content) {
1163 $styles = LF . implode(LF, $this->inDocStylesArray);
1164 $content = str_replace('/*###POSTCSSMARKER###*/', $styles, $content);
1165
1166 // Insert accumulated JS
1167 $jscode = $this->JScode . LF . $this->wrapScriptTags(implode(LF, $this->JScodeArray));
1168 $content = str_replace('<!--###POSTJSMARKER###-->', $jscode, $content);
1169 return $content;
1170 }
1171
1172 /**
1173 * Returns an array of all stylesheet directories belonging to core and skins
1174 *
1175 * @return array Stylesheet directories
1176 */
1177 public function getSkinStylesheetDirectories() {
1178 $stylesheetDirectories = array();
1179 // Add default core stylesheets
1180 foreach ($this->stylesheetsCore as $stylesheetDir) {
1181 $stylesheetDirectories[] = $stylesheetDir;
1182 }
1183 // Stylesheets from skins
1184 // merge default css directories ($this->stylesheetsSkin) with additional ones and include them
1185 if (is_array($GLOBALS['TBE_STYLES']['skins'])) {
1186 // loop over all registered skins
1187 foreach ($GLOBALS['TBE_STYLES']['skins'] as $skinExtKey => $skin) {
1188 $skinStylesheetDirs = $this->stylesheetsSkins;
1189 // Skins can add custom stylesheetDirectories using
1190 // $GLOBALS['TBE_STYLES']['skins'][$_EXTKEY]['stylesheetDirectories']
1191 if (is_array($skin['stylesheetDirectories'])) {
1192 $skinStylesheetDirs = array_merge($skinStylesheetDirs, $skin['stylesheetDirectories']);
1193 }
1194 // Add all registered directories
1195 foreach ($skinStylesheetDirs as $stylesheetDir) {
1196 // for EXT:myskin/stylesheets/ syntax
1197 if (substr($stylesheetDir, 0, 4) === 'EXT:') {
1198 list($extKey, $path) = explode('/', substr($stylesheetDir, 4), 2);
1199 if (!empty($extKey) && ExtensionManagementUtility::isLoaded($extKey) && !empty($path)) {
1200 $stylesheetDirectories[] = ExtensionManagementUtility::extRelPath($extKey) . $path;
1201 }
1202 } else {
1203 // For relative paths
1204 $stylesheetDirectories[] = ExtensionManagementUtility::extRelPath($skinExtKey) . $stylesheetDir;
1205 }
1206 }
1207 }
1208 }
1209 return $stylesheetDirectories;
1210 }
1211
1212 /**
1213 * Returns generator meta tag
1214 *
1215 * @return string <meta> tag with name "generator
1216 */
1217 public function generator() {
1218 $str = 'TYPO3 CMS, ' . TYPO3_URL_GENERAL . ', &#169; Kasper Sk&#229;rh&#248;j ' . TYPO3_copyright_year . ', extensions are copyright of their respective owners.';
1219 return '<meta name="generator" content="' . $str . '" />';
1220 }
1221
1222 /**
1223 * Returns X-UA-Compatible meta tag
1224 *
1225 * @param string $content Content of the compatible tag (default: IE-8)
1226 * @return string <meta http-equiv="X-UA-Compatible" content="???" />
1227 */
1228 public function xUaCompatible($content = 'IE=8') {
1229 return '<meta http-equiv="X-UA-Compatible" content="' . $content . '" />';
1230 }
1231
1232 /*****************************************
1233 *
1234 * OTHER ELEMENTS
1235 * Tables, buttons, formatting dimmed/red strings
1236 *
1237 ******************************************/
1238 /**
1239 * Returns an image-tag with an 18x16 icon of the following types:
1240 *
1241 * $type:
1242 * -1: OK icon (Check-mark)
1243 * 1: Notice (Speach-bubble)
1244 * 2: Warning (Yellow triangle)
1245 * 3: Fatal error (Red stop sign)
1246 *
1247 * @param int $type See description
1248 * @param string $styleAttribValue Value for style attribute
1249 * @return string HTML image tag (if applicable)
1250 */
1251 public function icons($type, $styleAttribValue = '') {
1252 switch ($type) {
1253 case self::STATUS_ICON_ERROR:
1254 $icon = 'status-dialog-error';
1255 break;
1256 case self::STATUS_ICON_WARNING:
1257 $icon = 'status-dialog-warning';
1258 break;
1259 case self::STATUS_ICON_NOTIFICATION:
1260 $icon = 'status-dialog-notification';
1261 break;
1262 case self::STATUS_ICON_OK:
1263 $icon = 'status-dialog-ok';
1264 break;
1265 default:
1266 // Do nothing
1267 }
1268 if ($icon) {
1269 return IconUtility::getSpriteIcon($icon);
1270 }
1271 }
1272
1273 /**
1274 * Returns an <input> button with the $onClick action and $label
1275 *
1276 * @param string $onClick The value of the onclick attribute of the input tag (submit type)
1277 * @param string $label The label for the button (which will be htmlspecialchar'ed)
1278 * @return string A <input> tag of the type "submit
1279 */
1280 public function t3Button($onClick, $label) {
1281 $button = '<input class="btn btn-default" type="submit" onclick="' . htmlspecialchars($onClick) . '; return false;" value="' . htmlspecialchars($label) . '" />';
1282 return $button;
1283 }
1284
1285 /**
1286 * Dimmed-fontwrap. Returns the string wrapped in a <span>-tag defining the color to be gray/dimmed
1287 *
1288 * @param string $string Input string
1289 * @return string Output string
1290 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use proper HTML directly
1291 */
1292 public function dfw($string) {
1293 GeneralUtility::logDeprecatedFunction();
1294 return '<span class="text-muted">' . $string . '</span>';
1295 }
1296
1297 /**
1298 * red-fontwrap. Returns the string wrapped in a <span>-tag defining the color to be red
1299 *
1300 * @param string $string Input string
1301 * @return string Output string
1302 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use proper HTML directly
1303 */
1304 public function rfw($string) {
1305 GeneralUtility::logDeprecatedFunction();
1306 return '<span class="text-danger">' . $string . '</span>';
1307 }
1308
1309 /**
1310 * Returns string wrapped in CDATA "tags" for XML / XHTML (wrap content of <script> and <style> sections in those!)
1311 *
1312 * @param string $string Input string
1313 * @return string Output string
1314 */
1315 public function wrapInCData($string) {
1316 $string = '/*<![CDATA[*/' . $string . '/*]]>*/';
1317 return $string;
1318 }
1319
1320 /**
1321 * Wraps the input string in script tags.
1322 * Automatic re-identing of the JS code is done by using the first line as ident reference.
1323 * This is nice for identing JS code with PHP code on the same level.
1324 *
1325 * @param string $string Input string
1326 * @param bool $linebreak Wrap script element in linebreaks? Default is TRUE.
1327 * @return string Output string
1328 */
1329 public function wrapScriptTags($string, $linebreak = TRUE) {
1330 if (trim($string)) {
1331 // <script wrapped in nl?
1332 $cr = $linebreak ? LF : '';
1333 // Remove nl from the beginning
1334 $string = ltrim($string, LF);
1335 // Re-ident to one tab using the first line as reference
1336 if ($string[0] === TAB) {
1337 $string = TAB . ltrim($string, TAB);
1338 }
1339 $string = $cr . '<script type="text/javascript">
1340 /*<![CDATA[*/
1341 ' . $string . '
1342 /*]]>*/
1343 </script>' . $cr;
1344 }
1345 return trim($string);
1346 }
1347
1348 // These vars defines the layout for the table produced by the table() function.
1349 // You can override these values from outside if you like.
1350 public $tableLayout = array(
1351 'defRow' => array(
1352 'defCol' => array('<td valign="top">', '</td>')
1353 )
1354 );
1355
1356 public $table_TR = '<tr>';
1357
1358 public $table_TABLE = '<table border="0" cellspacing="0" cellpadding="0" class="typo3-dblist" id="typo3-tmpltable">';
1359
1360 /**
1361 * Returns a table based on the input $data
1362 *
1363 * @param array $data Multidim array with first levels = rows, second levels = cells
1364 * @param array $layout If set, then this provides an alternative layout array instead of $this->tableLayout
1365 * @return string The HTML table.
1366 * @internal
1367 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
1368 */
1369 public function table($data, $layout = NULL) {
1370 GeneralUtility::logDeprecatedFunction();
1371 $result = '';
1372 if (is_array($data)) {
1373 $tableLayout = is_array($layout) ? $layout : $this->tableLayout;
1374 $rowCount = 0;
1375 foreach ($data as $tableRow) {
1376 if ($rowCount % 2) {
1377 $layout = is_array($tableLayout['defRowOdd']) ? $tableLayout['defRowOdd'] : $tableLayout['defRow'];
1378 } else {
1379 $layout = is_array($tableLayout['defRowEven']) ? $tableLayout['defRowEven'] : $tableLayout['defRow'];
1380 }
1381 $rowLayout = is_array($tableLayout[$rowCount]) ? $tableLayout[$rowCount] : $layout;
1382 $rowResult = '';
1383 if (is_array($tableRow)) {
1384 $cellCount = 0;
1385 foreach ($tableRow as $tableCell) {
1386 $cellWrap = is_array($layout[$cellCount]) ? $layout[$cellCount] : $layout['defCol'];
1387 $cellWrap = is_array($rowLayout['defCol']) ? $rowLayout['defCol'] : $cellWrap;
1388 $cellWrap = is_array($rowLayout[$cellCount]) ? $rowLayout[$cellCount] : $cellWrap;
1389 $rowResult .= $cellWrap[0] . $tableCell . $cellWrap[1];
1390 $cellCount++;
1391 }
1392 }
1393 $rowWrap = is_array($layout['tr']) ? $layout['tr'] : array($this->table_TR, '</tr>');
1394 $rowWrap = is_array($rowLayout['tr']) ? $rowLayout['tr'] : $rowWrap;
1395 $result .= $rowWrap[0] . $rowResult . $rowWrap[1];
1396 $rowCount++;
1397 }
1398 $tableWrap = is_array($tableLayout['table']) ? $tableLayout['table'] : array($this->table_TABLE, '</table>');
1399 $result = $tableWrap[0] . $result . $tableWrap[1];
1400 }
1401 return $result;
1402 }
1403
1404 /**
1405 * Constructs a table with content from the $arr1, $arr2 and $arr3.
1406 *
1407 * @param array $arr1 Menu elements on first level
1408 * @param array $arr2 Secondary items
1409 * @param array $arr3 Third-level items
1410 * @return string HTML content, <table>...</table>
1411 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
1412 */
1413 public function menuTable($arr1, $arr2 = array(), $arr3 = array()) {
1414 GeneralUtility::logDeprecatedFunction();
1415 $rows = max(array(count($arr1), count($arr2), count($arr3)));
1416 $menu = '
1417 <table border="0" cellpadding="0" cellspacing="0" id="typo3-tablemenu">';
1418 for ($a = 0; $a < $rows; $a++) {
1419 $menu .= '<tr>';
1420 $cls = array();
1421 $valign = 'middle';
1422 $cls[] = '<td valign="' . $valign . '">' . $arr1[$a][0] . '</td><td>' . $arr1[$a][1] . '</td>';
1423 if (!empty($arr2)) {
1424 $cls[] = '<td valign="' . $valign . '">' . $arr2[$a][0] . '</td><td>' . $arr2[$a][1] . '</td>';
1425 if (!empty($arr3)) {
1426 $cls[] = '<td valign="' . $valign . '">' . $arr3[$a][0] . '</td><td>' . $arr3[$a][1] . '</td>';
1427 }
1428 }
1429 $menu .= implode($cls, '<td>&nbsp;&nbsp;</td>');
1430 $menu .= '</tr>';
1431 }
1432 $menu .= '
1433 </table>
1434 ';
1435 return $menu;
1436 }
1437
1438 /**
1439 * Returns a one-row/two-celled table with $content and $menu side by side.
1440 * The table is a 100% width table and each cell is aligned left / right
1441 *
1442 * @param string $content Content cell content (left)
1443 * @param string $menu Menu cell content (right)
1444 * @return string HTML output
1445 */
1446 public function funcMenu($content, $menu) {
1447 return '
1448 <table border="0" cellpadding="0" cellspacing="0" width="100%" id="typo3-funcmenu">
1449 <tr>
1450 <td valign="top" nowrap="nowrap">' . $content . '</td>
1451 <td valign="top" align="right" nowrap="nowrap">' . $menu . '</td>
1452 </tr>
1453 </table>';
1454 }
1455
1456 /**
1457 * Includes a javascript library that exists in the core /typo3/ directory
1458 *
1459 * @param string $lib: Library name. Call it with the full path like "sysext/core/Resources/Public/JavaScript/QueryGenerator.js" to load it
1460 * @return void
1461 */
1462 public function loadJavascriptLib($lib) {
1463 // @todo: maybe we can remove this one as well
1464 $this->pageRenderer->addJsFile($lib);
1465 }
1466
1467 /**
1468 * Includes the necessary Javascript function for the clickmenu (context sensitive menus) in the document
1469 *
1470 * @return void
1471 */
1472 public function getContextMenuCode() {
1473 $this->pageRenderer->loadJquery();
1474 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ClickMenu');
1475 }
1476
1477 /**
1478 * Includes the necessary javascript file for use on pages which have the
1479 * drag and drop functionality (legacy folder tree)
1480 *
1481 * @param string $table indicator of which table the drag and drop function should work on (pages or folders)
1482 * @param string $additionalJavaScriptCode adds more code to the additional javascript code
1483 * @return void
1484 */
1485 public function getDragDropCode($table, $additionalJavaScriptCode = '') {
1486 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LegacyTree', 'function() {
1487 DragDrop.table = "' . $table . '";
1488 ' . $additionalJavaScriptCode . '
1489 }');
1490 }
1491
1492 /**
1493 * This loads everything needed for the Context Sensitive Help (CSH)
1494 *
1495 * @return void
1496 */
1497 protected function loadCshJavascript() {
1498 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ContextHelp');
1499 $this->pageRenderer->addInlineSetting('ContextHelp', 'moduleUrl', BackendUtility::getModuleUrl('help_cshmanual'));
1500 }
1501
1502 /**
1503 * Creates a tab menu from an array definition
1504 *
1505 * Returns a tab menu for a module
1506 * Requires the JS function jumpToUrl() to be available
1507 *
1508 * @param mixed $mainParams is the "&id=" parameter value to be sent to the module, but it can be also a parameter array which will be passed instead of the &id=...
1509 * @param string $elementName it the form elements name, probably something like "SET[...]
1510 * @param string $currentValue is the value to be selected currently.
1511 * @param array $menuItems is an array with the menu items for the selector box
1512 * @param string $script is the script to send the &id to, if empty it's automatically found
1513 * @param string $addparams is additional parameters to pass to the script.
1514 * @return string HTML code for tab menu
1515 */
1516 public function getTabMenu($mainParams, $elementName, $currentValue, $menuItems, $script = '', $addparams = '') {
1517 $content = '';
1518 if (is_array($menuItems)) {
1519 if (!is_array($mainParams)) {
1520 $mainParams = array('id' => $mainParams);
1521 }
1522 $mainParams = GeneralUtility::implodeArrayForUrl('', $mainParams);
1523 if (!$script) {
1524 $script = basename(PATH_thisScript);
1525 }
1526 $menuDef = array();
1527 foreach ($menuItems as $value => $label) {
1528 $menuDef[$value]['isActive'] = (string)$currentValue === (string)$value;
1529 $menuDef[$value]['label'] = htmlspecialchars($label, ENT_COMPAT, 'UTF-8', FALSE);
1530 $menuDef[$value]['url'] = $script . '?' . $mainParams . $addparams . '&' . $elementName . '=' . $value;
1531 }
1532 $content = $this->getTabMenuRaw($menuDef);
1533 }
1534 return $content;
1535 }
1536
1537 /**
1538 * Creates the HTML content for the tab menu
1539 *
1540 * @param array $menuItems Menu items for tabs
1541 * @return string Table HTML
1542 * @access private
1543 */
1544 public function getTabMenuRaw($menuItems) {
1545 if (!is_array($menuItems)) {
1546 return '';
1547 }
1548
1549 $options = '';
1550 foreach ($menuItems as $id => $def) {
1551 $class = $def['isActive'] ? 'active' : '';
1552 $label = $def['label'];
1553 $url = htmlspecialchars($def['url']);
1554 $params = $def['addParams'];
1555
1556 $options .= '<li class="' . $class . '">' .
1557 '<a href="' . $url . '" ' . $params . '>' . $label . '</a>' .
1558 '</li>';
1559 }
1560
1561 return '<ul class="nav nav-tabs" role="tablist">' .
1562 $options .
1563 '</ul>';
1564
1565 }
1566
1567 /**
1568 * Creates a DYNAMIC tab-menu where the tabs or collapseable are rendered with bootstrap markup
1569 *
1570 * @param array $menuItems Numeric array where each entry is an array in itself with associative keys: "label" contains the label for the TAB, "content" contains the HTML content that goes into the div-layer of the tabs content. "description" contains description text to be shown in the layer. "linkTitle" is short text for the title attribute of the tab-menu link (mouse-over text of tab). "stateIcon" indicates a standard status icon (see ->icon(), values: -1, 1, 2, 3). "icon" is an image tag placed before the text.
1571 * @param string $identString Identification string. This should be unique for every instance of a dynamic menu!
1572 * @param int $defaultTabIndex Default tab to open (for toggle <=0). Value corresponds to integer-array index + 1 (index zero is "1", index "1" is 2 etc.). A value of zero (or something non-existing) will result in no default tab open.
1573 * @param bool $collapseable If set, the tabs are rendered as headers instead over each sheet. Effectively this means there is no tab menu, but rather a foldout/foldin menu.
1574 * @param bool $wrapContent If set, the content is wrapped in div structure which provides a padding and border style. Set this FALSE to get unstyled content pane with fullsize content area.
1575 * @param bool $storeLastActiveTab If set, the last open tab is stored in local storage and will be re-open again. If you don't need this feature, e.g. for wizards like import/export you can disable this behaviour.
1576 * @return string
1577 */
1578 public function getDynamicTabMenu(array $menuItems, $identString, $defaultTabIndex = 1, $collapseable = FALSE, $wrapContent = TRUE, $storeLastActiveTab = TRUE) {
1579 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Tabs');
1580 $templatePathAndFileName = 'EXT:backend/Resources/Private/Templates/DocumentTemplate/' . ($collapseable ? 'Collapse.html' : 'Tabs.html');
1581 $view = GeneralUtility::makeInstance(StandaloneView::class);
1582 $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templatePathAndFileName));
1583 $view->assignMultiple(array(
1584 'id' => $this->getDynTabMenuId($identString),
1585 'items' => $menuItems,
1586 'defaultTabIndex' => $defaultTabIndex,
1587 'wrapContent' => $wrapContent,
1588 'storeLastActiveTab' => $storeLastActiveTab,
1589 'BACK_PATH' => $GLOBALS['BACK_PATH']
1590 ));
1591 return $view->render();
1592 }
1593
1594 /**
1595 * Creates a DYNAMIC tab-menu where the tabs are switched between with DHTML.
1596 * Should work in MSIE, Mozilla, Opera and Konqueror. On Konqueror I did find a serious problem: <textarea> fields loose their content when you switch tabs!
1597 *
1598 * @param array $menuItems Numeric array where each entry is an array in itself with associative keys: "label" contains the label for the TAB, "content" contains the HTML content that goes into the div-layer of the tabs content. "description" contains description text to be shown in the layer. "linkTitle" is short text for the title attribute of the tab-menu link (mouse-over text of tab). "stateIcon" indicates a standard status icon (see ->icon(), values: -1, 1, 2, 3). "icon" is an image tag placed before the text.
1599 * @param string $identString Identification string. This should be unique for every instance of a dynamic menu!
1600 * @param int $toggle If "1", then enabling one tab does not hide the others - they simply toggles each sheet on/off. This makes most sense together with the $foldout option. If "-1" then it acts normally where only one tab can be active at a time BUT you can click a tab and it will close so you have no active tabs.
1601 * @param bool $foldout If set, the tabs are rendered as headers instead over each sheet. Effectively this means there is no tab menu, but rather a foldout/foldin menu. Make sure to set $toggle as well for this option.
1602 * @param bool $noWrap Deprecated - delivered by CSS
1603 * @param bool $fullWidth If set, the tabs will span the full width of their position
1604 * @param int $defaultTabIndex Default tab to open (for toggle <=0). Value corresponds to integer-array index + 1 (index zero is "1", index "1" is 2 etc.). A value of zero (or something non-existing) will result in no default tab open.
1605 * @param int $tabBehaviour If set to '1' empty tabs will be remove, If set to '2' empty tabs will be disabled. setting this option to '2' is deprecated since TYPO3 CMS 7, and will be removed iwth CMS 8
1606 * @return string JavaScript section for the HTML header.
1607 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
1608 */
1609 public function getDynTabMenu($menuItems, $identString, $toggle = 0, $foldout = FALSE, $noWrap = TRUE, $fullWidth = FALSE, $defaultTabIndex = 1, $tabBehaviour = 1) {
1610 GeneralUtility::logDeprecatedFunction();
1611 return $this->getDynamicTabMenu($menuItems, $identString, $defaultTabIndex, $foldout, $noWrap);
1612 }
1613
1614 /**
1615 * Creates the id for dynTabMenus.
1616 *
1617 * @param string $identString Identification string. This should be unique for every instance of a dynamic menu!
1618 * @return string The id with a short MD5 of $identString and prefixed "DTM-", like "DTM-2e8791854a
1619 */
1620 public function getDynTabMenuId($identString) {
1621 $id = 'DTM-' . GeneralUtility::shortMD5($identString);
1622 return $id;
1623 }
1624
1625 /**
1626 * Creates the version selector for the page id inputted.
1627 * Requires the core version management extension, "version" to be loaded.
1628 *
1629 * @param int $id Page id to create selector for.
1630 * @param bool $noAction If set, there will be no button for swapping page.
1631 * @return string
1632 */
1633 public function getVersionSelector($id, $noAction = FALSE) {
1634 if (
1635 ExtensionManagementUtility::isLoaded('version') &&
1636 !ExtensionManagementUtility::isLoaded('workspaces')
1637 ) {
1638 $versionGuiObj = GeneralUtility::makeInstance(\TYPO3\CMS\Version\View\VersionView::class);
1639 return $versionGuiObj->getVersionSelector($id, $noAction);
1640 }
1641 }
1642
1643 /**
1644 * Function to load a HTML template file with markers.
1645 * When calling from own extension, use syntax getHtmlTemplate('EXT:extkey/template.html')
1646 *
1647 * @param string $filename tmpl name, usually in the typo3/template/ directory
1648 * @return string HTML of template
1649 */
1650 public function getHtmlTemplate($filename) {
1651 // setting the name of the original HTML template
1652 $this->moduleTemplateFilename = $filename;
1653 if ($GLOBALS['TBE_STYLES']['htmlTemplates'][$filename]) {
1654 $filename = $GLOBALS['TBE_STYLES']['htmlTemplates'][$filename];
1655 }
1656 if (GeneralUtility::isFirstPartOfStr($filename, 'EXT:')) {
1657 $filename = GeneralUtility::getFileAbsFileName($filename, TRUE, TRUE);
1658 } elseif (!GeneralUtility::isAbsPath($filename)) {
1659 $filename = GeneralUtility::resolveBackPath($filename);
1660 } elseif (!GeneralUtility::isAllowedAbsPath($filename)) {
1661 $filename = '';
1662 }
1663 $htmlTemplate = '';
1664 if ($filename !== '') {
1665 $htmlTemplate = GeneralUtility::getUrl($filename);
1666 }
1667 return $htmlTemplate;
1668 }
1669
1670 /**
1671 * Define the template for the module
1672 *
1673 * @param string $filename filename
1674 * @return void
1675 */
1676 public function setModuleTemplate($filename) {
1677 $this->moduleTemplate = $this->getHtmlTemplate($filename);
1678 }
1679
1680 /**
1681 * Put together the various elements for the module <body> using a static HTML
1682 * template
1683 *
1684 * @param array $pageRecord Record of the current page, used for page path and info
1685 * @param array $buttons HTML for all buttons
1686 * @param array $markerArray HTML for all other markers
1687 * @param array $subpartArray HTML for the subparts
1688 * @return string Composite HTML
1689 */
1690 public function moduleBody($pageRecord = array(), $buttons = array(), $markerArray = array(), $subpartArray = array()) {
1691 // Get the HTML template for the module
1692 $moduleBody = HtmlParser::getSubpart($this->moduleTemplate, '###FULLDOC###');
1693 // Add CSS
1694 $this->inDocStylesArray[] = 'html { overflow: hidden; }';
1695 // Get the page path for the docheader
1696 $markerArray['PAGEPATH'] = $this->getPagePath($pageRecord);
1697 // Get the page info for the docheader
1698 $markerArray['PAGEINFO'] = $this->getPageInfo($pageRecord);
1699 // Get all the buttons for the docheader
1700 $docHeaderButtons = $this->getDocHeaderButtons($buttons);
1701 // Merge docheader buttons with the marker array
1702 $markerArray = array_merge($markerArray, $docHeaderButtons);
1703 // replacing subparts
1704 foreach ($subpartArray as $marker => $content) {
1705 $moduleBody = HtmlParser::substituteSubpart($moduleBody, $marker, $content);
1706 }
1707 // adding flash messages
1708 if ($this->showFlashMessages) {
1709 $flashMessages = $this->getFlashMessages();
1710 if (!empty($flashMessages)) {
1711 $markerArray['FLASHMESSAGES'] = $flashMessages;
1712 // If there is no dedicated marker for the messages present
1713 // then force them to appear before the content
1714 if (strpos($moduleBody, '###FLASHMESSAGES###') === FALSE) {
1715 $moduleBody = str_replace('###CONTENT###', '###FLASHMESSAGES######CONTENT###', $moduleBody);
1716 }
1717 }
1718 }
1719 // Hook for adding more markers/content to the page, like the version selector
1720 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['moduleBodyPostProcess'])) {
1721 $params = array(
1722 'moduleTemplateFilename' => &$this->moduleTemplateFilename,
1723 'moduleTemplate' => &$this->moduleTemplate,
1724 'moduleBody' => &$moduleBody,
1725 'markers' => &$markerArray,
1726 'parentObject' => &$this
1727 );
1728 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['moduleBodyPostProcess'] as $funcRef) {
1729 GeneralUtility::callUserFunction($funcRef, $params, $this);
1730 }
1731 }
1732 // Replacing all markers with the finished markers and return the HTML content
1733 return HtmlParser::substituteMarkerArray($moduleBody, $markerArray, '###|###');
1734 }
1735
1736 /**
1737 * Get the default rendered FlashMessages from queue
1738 *
1739 * @return string
1740 */
1741 public function getFlashMessages() {
1742 /** @var $flashMessageService \TYPO3\CMS\Core\Messaging\FlashMessageService */
1743 $flashMessageService = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessageService::class);
1744 /** @var $defaultFlashMessageQueue \TYPO3\CMS\Core\Messaging\FlashMessageQueue */
1745 $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
1746 return $defaultFlashMessageQueue->renderFlashMessages();
1747 }
1748
1749 /**
1750 * Renders the FlashMessages from queue and returns them as AJAX.
1751 *
1752 * @param array $params Always empty.
1753 * @param \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxObj The AjaxRequestHandler object used to return content and set content types
1754 * @return void
1755 */
1756 public function renderFlashMessages(array $params, \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxObj) {
1757 $ajaxObj->addContent('result', $this->getFlashMessages());
1758 $ajaxObj->setContentFormat('html');
1759 }
1760
1761 /**
1762 * Fill the button lists with the defined HTML
1763 *
1764 * @param array $buttons HTML for all buttons
1765 * @return array Containing HTML for both buttonlists
1766 */
1767 protected function getDocHeaderButtons($buttons) {
1768 $markers = array();
1769 // Fill buttons for left and right float
1770 $floats = array('left', 'right');
1771 foreach ($floats as $key) {
1772 // Get the template for each float
1773 $buttonTemplate = HtmlParser::getSubpart($this->moduleTemplate, '###BUTTON_GROUPS_' . strtoupper($key) . '###');
1774 // Fill the button markers in this float
1775 $buttonTemplate = HtmlParser::substituteMarkerArray($buttonTemplate, $buttons, '###|###', TRUE);
1776 // getting the wrap for each group
1777 $buttonWrap = HtmlParser::getSubpart($this->moduleTemplate, '###BUTTON_GROUP_WRAP###');
1778 // looping through the groups (max 6) and remove the empty groups
1779 for ($groupNumber = 1; $groupNumber < 6; $groupNumber++) {
1780 $buttonMarker = '###BUTTON_GROUP' . $groupNumber . '###';
1781 $buttonGroup = HtmlParser::getSubpart($buttonTemplate, $buttonMarker);
1782 if (trim($buttonGroup)) {
1783 if ($buttonWrap) {
1784 $buttonGroup = HtmlParser::substituteMarker($buttonWrap, '###BUTTONS###', $buttonGroup);
1785 }
1786 $buttonTemplate = HtmlParser::substituteSubpart($buttonTemplate, $buttonMarker, trim($buttonGroup));
1787 }
1788 }
1789 // Replace the marker with the template and remove all line breaks (for IE compat)
1790 $markers['BUTTONLIST_' . strtoupper($key)] = str_replace(LF, '', $buttonTemplate);
1791 }
1792 // Hook for manipulating docHeaderButtons
1793 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['docHeaderButtonsHook'])) {
1794 $params = array(
1795 'buttons' => $buttons,
1796 'markers' => &$markers,
1797 'pObj' => &$this
1798 );
1799 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['docHeaderButtonsHook'] as $funcRef) {
1800 GeneralUtility::callUserFunction($funcRef, $params, $this);
1801 }
1802 }
1803 return $markers;
1804 }
1805
1806 /**
1807 * Generate the page path for docheader
1808 *
1809 * @param array $pageRecord Current page
1810 * @return string Page path
1811 */
1812 protected function getPagePath($pageRecord) {
1813 // Is this a real page
1814 if (is_array($pageRecord) && $pageRecord['uid']) {
1815 $title = substr($pageRecord['_thePathFull'], 0, -1);
1816 // Remove current page title
1817 $pos = strrpos($title, $pageRecord['title']);
1818 if ($pos !== FALSE) {
1819 $title = substr($title, 0, $pos);
1820 }
1821 } else {
1822 $title = '';
1823 }
1824 // Setting the path of the page
1825 $pagePath = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.path', TRUE) . ': <span class="typo3-docheader-pagePath">';
1826 // crop the title to title limit (or 50, if not defined)
1827 $cropLength = empty($GLOBALS['BE_USER']->uc['titleLen']) ? 50 : $GLOBALS['BE_USER']->uc['titleLen'];
1828 $croppedTitle = GeneralUtility::fixed_lgd_cs($title, -$cropLength);
1829 if ($croppedTitle !== $title) {
1830 $pagePath .= '<abbr title="' . htmlspecialchars($title) . '">' . htmlspecialchars($croppedTitle) . '</abbr>';
1831 } else {
1832 $pagePath .= htmlspecialchars($title);
1833 }
1834 $pagePath .= '</span>';
1835 return $pagePath;
1836 }
1837
1838 /**
1839 * Setting page icon with clickmenu + uid for docheader
1840 *
1841 * @param array $pageRecord Current page
1842 * @return string Page info
1843 */
1844 protected function getPageInfo($pageRecord) {
1845 // Add icon with clickmenu, etc:
1846 // If there IS a real page
1847 if (is_array($pageRecord) && $pageRecord['uid']) {
1848 $alttext = BackendUtility::getRecordIconAltText($pageRecord, 'pages');
1849 $iconImg = IconUtility::getSpriteIconForRecord('pages', $pageRecord, array('title' => $alttext));
1850 // Make Icon:
1851 $theIcon = $GLOBALS['SOBE']->doc->wrapClickMenuOnIcon($iconImg, 'pages', $pageRecord['uid']);
1852 $uid = $pageRecord['uid'];
1853 $title = BackendUtility::getRecordTitle('pages', $pageRecord);
1854 } else {
1855 // On root-level of page tree
1856 // Make Icon
1857 $iconImg = IconUtility::getSpriteIcon('apps-pagetree-root', array('title' => htmlspecialchars($GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'])));
1858 if ($GLOBALS['BE_USER']->user['admin']) {
1859 $theIcon = $GLOBALS['SOBE']->doc->wrapClickMenuOnIcon($iconImg, 'pages', 0);
1860 } else {
1861 $theIcon = $iconImg;
1862 }
1863 $uid = '0';
1864 $title = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'];
1865 }
1866 // Setting icon with clickmenu + uid
1867 $pageInfo = $theIcon . '<strong>' . htmlspecialchars($title) . '&nbsp;[' . $uid . ']</strong>';
1868 return $pageInfo;
1869 }
1870
1871 /**
1872 * Makes a collapseable section. See reports module for an example
1873 *
1874 * @param string $title
1875 * @param string $html
1876 * @param string $id
1877 * @param string $saveStatePointer
1878 * @return string
1879 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. Use HTML bootstrap classes, localStorage etc.
1880 */
1881 public function collapseableSection($title, $html, $id, $saveStatePointer = '') {
1882 GeneralUtility::logDeprecatedFunction();
1883 $hasSave = (bool)$saveStatePointer;
1884 $collapsedStyle = ($collapsedClass = '');
1885 if ($hasSave) {
1886 /** @var $userSettingsController \TYPO3\CMS\Backend\Controller\UserSettingsController */
1887 $userSettingsController = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Controller\UserSettingsController::class);
1888 $value = $userSettingsController->process('get', $saveStatePointer . '.' . $id);
1889 if ($value) {
1890 $collapsedStyle = ' style="display: none"';
1891 $collapsedClass = ' collapsed';
1892 } else {
1893 $collapsedStyle = '';
1894 $collapsedClass = ' expanded';
1895 }
1896 }
1897 $this->pageRenderer->loadExtJS();
1898 $this->pageRenderer->addExtOnReadyCode('
1899 Ext.select("h2.section-header").each(function(element){
1900 element.on("click", function(event, tag) {
1901 var state = 0,
1902 el = Ext.fly(tag),
1903 div = el.next("div"),
1904 saveKey = el.getAttribute("rel");
1905 if (el.hasClass("collapsed")) {
1906 el.removeClass("collapsed").addClass("expanded");
1907 div.slideIn("t", {
1908 easing: "easeIn",
1909 duration: .5
1910 });
1911 } else {
1912 el.removeClass("expanded").addClass("collapsed");
1913 div.slideOut("t", {
1914 easing: "easeOut",
1915 duration: .5,
1916 remove: false,
1917 useDisplay: true
1918 });
1919 state = 1;
1920 }
1921 if (saveKey) {
1922 try {
1923 top.TYPO3.Storage.Persistent.set(saveKey + "." + tag.id, state);
1924 } catch(e) {}
1925 }
1926 });
1927 });
1928 ');
1929 return '
1930 <h2 id="' . $id . '" class="section-header' . $collapsedClass . '" rel="' . $saveStatePointer . '"> ' . $title . '</h2>
1931 <div' . $collapsedStyle . '>' . $html . '</div>
1932 ';
1933 }
1934
1935 /**
1936 * Retrieves configured favicon for backend (with fallback)
1937 *
1938 * @return string
1939 */
1940 protected function getBackendFavicon() {
1941 return $GLOBALS['TBE_STYLES']['favicon'] ?: 'sysext/backend/Resources/Public/Icons/favicon.ico';
1942 }
1943
1944 }