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