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