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